PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/includes/net/dns2/updater.php

https://bitbucket.org/speedealing/speedealing
PHP | 653 lines | 208 code | 68 blank | 377 comment | 21 complexity | dfaa7a83cb978bc6496956df253ed046 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * DNS Library for handling lookups and updates.
  5. *
  6. * PHP Version 5
  7. *
  8. * Copyright (c) 2010, Mike Pultz <mike@mikepultz.com>.
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. *
  15. * * Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. *
  18. * * Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in
  20. * the documentation and/or other materials provided with the
  21. * distribution.
  22. *
  23. * * Neither the name of Mike Pultz nor the names of his contributors
  24. * may be used to endorse or promote products derived from this
  25. * software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  30. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  31. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  33. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  35. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * @category Networking
  41. * @package Net_DNS2
  42. * @author Mike Pultz <mike@mikepultz.com>
  43. * @copyright 2010 Mike Pultz <mike@mikepultz.com>
  44. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  45. * @version SVN: $Id: Updater.php 177 2012-11-16 05:04:47Z mike.pultz $
  46. * @link http://pear.php.net/package/Net_DNS2
  47. * @since File available since Release 0.6.0
  48. *
  49. */
  50. /**
  51. * The main dynamic DNS updater class.
  52. *
  53. * This class provices functions to handle all defined dynamic DNS update
  54. * requests as defined by RFC 2136.
  55. *
  56. * This is separate from the Net_DNS2_Resolver class, as while the underlying
  57. * protocol is the same, the functionality is completely different.
  58. *
  59. * Generally, query (recursive) lookups are done against caching server, while
  60. * update requests are done against authoratative servers.
  61. *
  62. * @category Networking
  63. * @package Net_DNS2
  64. * @author Mike Pultz <mike@mikepultz.com>
  65. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  66. * @link http://pear.php.net/package/Net_DNS2
  67. * @see Net_DNS2
  68. *
  69. */
  70. class Net_DNS2_Updater extends Net_DNS2
  71. {
  72. /*
  73. * a Net_DNS2_Packet_Request object used for the update request
  74. */
  75. private $_packet;
  76. /**
  77. * Constructor - builds a new Net_DNS2_Updater objected used for doing
  78. * dynamic DNS updates
  79. *
  80. * @param string $zone the domain name to use for DNS updates
  81. * @param mixed $options an array of config options or null
  82. *
  83. * @throws Net_DNS2_Exception
  84. * @access public
  85. *
  86. */
  87. public function __construct($zone, array $options = null)
  88. {
  89. parent::__construct($options);
  90. //
  91. // create the packet
  92. //
  93. $this->_packet = new Net_DNS2_Packet_Request(
  94. strtolower(trim($zone, " \n\r\t.")), 'SOA', 'IN'
  95. );
  96. //
  97. // make sure the opcode on the packet is set to UPDATE
  98. //
  99. $this->_packet->header->opcode = Net_DNS2_Lookups::OPCODE_UPDATE;
  100. }
  101. /**
  102. * checks that the given name matches the name for the zone we're updating
  103. *
  104. * @param string $name The name to be checked.
  105. *
  106. * @return boolean
  107. * @throws Net_DNS2_Exception
  108. * @access private
  109. *
  110. */
  111. private function _checkName($name)
  112. {
  113. if (!preg_match('/' . $this->_packet->question[0]->qname . '$/', $name)) {
  114. throw new Net_DNS2_Exception(
  115. 'name provided (' . $name . ') does not match zone name (' .
  116. $this->_packet->question[0]->qname . ')',
  117. Net_DNS2_Lookups::E_PACKET_INVALID
  118. );
  119. }
  120. return true;
  121. }
  122. /**
  123. * add a signature to the request for authentication
  124. *
  125. * @param string $keyname the key name to use for the TSIG RR
  126. * @param string $signature the key to sign the request.
  127. *
  128. * @return boolean
  129. * @access public
  130. * @see Net_DNS2::signTSIG()
  131. * @deprecated function deprecated in 1.1.0
  132. *
  133. */
  134. public function signature($keyname, $signature)
  135. {
  136. return $this->signTSIG($keyname, $signature);
  137. }
  138. /**
  139. * 2.5.1 - Add To An RRset
  140. *
  141. * RRs are added to the Update Section whose NAME, TYPE, TTL, RDLENGTH
  142. * and RDATA are those being added, and CLASS is the same as the zone
  143. * class. Any duplicate RRs will be silently ignored by the primary
  144. * master.
  145. *
  146. * @param Net_DNS2_RR $rr the Net_DNS2_RR object to be added to the zone
  147. *
  148. * @return boolean
  149. * @throws Net_DNS2_Exception
  150. * @access public
  151. *
  152. */
  153. public function add(Net_DNS2_RR $rr)
  154. {
  155. $this->_checkName($rr->name);
  156. //
  157. // add the RR to the "update" section
  158. //
  159. if (!in_array($rr, $this->_packet->authority)) {
  160. $this->_packet->authority[] = $rr;
  161. }
  162. return true;
  163. }
  164. /**
  165. * 2.5.4 - Delete An RR From An RRset
  166. *
  167. * RRs to be deleted are added to the Update Section. The NAME, TYPE,
  168. * RDLENGTH and RDATA must match the RR being deleted. TTL must be
  169. * specified as zero (0) and will otherwise be ignored by the primary
  170. * master. CLASS must be specified as NONE to distinguish this from an
  171. * RR addition. If no such RRs exist, then this Update RR will be
  172. * silently ignored by the primary master.
  173. *
  174. * @param Net_DNS2_RR $rr the Net_DNS2_RR object to be deleted from the zone
  175. *
  176. * @return boolean
  177. * @throws Net_DNS2_Exception
  178. * @access public
  179. *
  180. */
  181. public function delete(Net_DNS2_RR $rr)
  182. {
  183. $this->_checkName($rr->name);
  184. $rr->ttl = 0;
  185. $rr->class = 'NONE';
  186. //
  187. // add the RR to the "update" section
  188. //
  189. if (!in_array($rr, $this->_packet->authority)) {
  190. $this->_packet->authority[] = $rr;
  191. }
  192. return true;
  193. }
  194. /**
  195. * 2.5.2 - Delete An RRset
  196. *
  197. * One RR is added to the Update Section whose NAME and TYPE are those
  198. * of the RRset to be deleted. TTL must be specified as zero (0) and is
  199. * otherwise not used by the primary master. CLASS must be specified as
  200. * ANY. RDLENGTH must be zero (0) and RDATA must therefore be empty.
  201. * If no such RRset exists, then this Update RR will be silently ignored
  202. * by the primary master
  203. *
  204. * @param string $name the RR name to be removed from the zone
  205. * @param string $type the RR type to be removed from the zone
  206. *
  207. * @return boolean
  208. * @throws Net_DNS2_Exception
  209. * @access public
  210. *
  211. */
  212. public function deleteAny($name, $type)
  213. {
  214. $this->_checkName($name);
  215. $class = Net_DNS2_Lookups::$rr_types_id_to_class[
  216. Net_DNS2_Lookups::$rr_types_by_name[$type]
  217. ];
  218. if (!isset($class)) {
  219. throw new Net_DNS2_Exception(
  220. 'unknown or un-supported resource record type: ' . $type,
  221. Net_DNS2_Lookups::E_RR_INVALID
  222. );
  223. }
  224. $rr = new $class;
  225. $rr->name = $name;
  226. $rr->ttl = 0;
  227. $rr->class = 'ANY';
  228. $rr->rdlength = -1;
  229. $rr->rdata = '';
  230. //
  231. // add the RR to the "update" section
  232. //
  233. if (!in_array($rr, $this->_packet->authority)) {
  234. $this->_packet->authority[] = $rr;
  235. }
  236. return true;
  237. }
  238. /**
  239. * 2.5.3 - Delete All RRsets From A Name
  240. *
  241. * One RR is added to the Update Section whose NAME is that of the name
  242. * to be cleansed of RRsets. TYPE must be specified as ANY. TTL must
  243. * be specified as zero (0) and is otherwise not used by the primary
  244. * master. CLASS must be specified as ANY. RDLENGTH must be zero (0)
  245. * and RDATA must therefore be empty. If no such RRsets exist, then
  246. * this Update RR will be silently ignored by the primary master.
  247. *
  248. * @param string $name the RR name to be removed from the zone
  249. *
  250. * @return boolean
  251. * @throws Net_DNS2_Exception
  252. * @access public
  253. *
  254. */
  255. public function deleteAll($name)
  256. {
  257. $this->_checkName($name);
  258. //
  259. // the Net_DNS2_RR_ANY class is just an empty stub class used for these
  260. // cases only
  261. //
  262. $rr = new Net_DNS2_RR_ANY;
  263. $rr->name = $name;
  264. $rr->ttl = 0;
  265. $rr->type = 'ANY';
  266. $rr->class = 'ANY';
  267. $rr->rdlength = -1;
  268. $rr->rdata = '';
  269. //
  270. // add the RR to the "update" section
  271. //
  272. if (!in_array($rr, $this->_packet->authority)) {
  273. $this->_packet->authority[] = $rr;
  274. }
  275. return true;
  276. }
  277. /**
  278. * 2.4.1 - RRset Exists (Value Independent)
  279. *
  280. * At least one RR with a specified NAME and TYPE (in the zone and class
  281. * specified in the Zone Section) must exist.
  282. *
  283. * For this prerequisite, a requestor adds to the section a single RR
  284. * whose NAME and TYPE are equal to that of the zone RRset whose
  285. * existence is required. RDLENGTH is zero and RDATA is therefore
  286. * empty. CLASS must be specified as ANY to differentiate this
  287. * condition from that of an actual RR whose RDLENGTH is naturally zero
  288. * (0) (e.g., NULL). TTL is specified as zero (0).
  289. *
  290. * @param string $name the RR name for the prerequisite
  291. * @param string $type the RR type for the prerequisite
  292. *
  293. * @return boolean
  294. * @throws Net_DNS2_Exception
  295. * @access public
  296. *
  297. */
  298. public function checkExists($name, $type)
  299. {
  300. $this->_checkName($name);
  301. $class = Net_DNS2_Lookups::$rr_types_id_to_class[
  302. Net_DNS2_Lookups::$rr_types_by_name[$type]
  303. ];
  304. if (!isset($class)) {
  305. throw new Net_DNS2_Exception(
  306. 'unknown or un-supported resource record type: ' . $type,
  307. Net_DNS2_Lookups::E_RR_INVALID
  308. );
  309. }
  310. $rr = new $class;
  311. $rr->name = $name;
  312. $rr->ttl = 0;
  313. $rr->class = 'ANY';
  314. $rr->rdlength = -1;
  315. $rr->rdata = '';
  316. //
  317. // add the RR to the "prerequisite" section
  318. //
  319. if (!in_array($rr, $this->_packet->answer)) {
  320. $this->_packet->answer[] = $rr;
  321. }
  322. return true;
  323. }
  324. /**
  325. * 2.4.2 - RRset Exists (Value Dependent)
  326. *
  327. * A set of RRs with a specified NAME and TYPE exists and has the same
  328. * members with the same RDATAs as the RRset specified here in this
  329. * section. While RRset ordering is undefined and therefore not
  330. * significant to this comparison, the sets be identical in their
  331. * extent.
  332. *
  333. * For this prerequisite, a requestor adds to the section an entire
  334. * RRset whose preexistence is required. NAME and TYPE are that of the
  335. * RRset being denoted. CLASS is that of the zone. TTL must be
  336. * specified as zero (0) and is ignored when comparing RRsets for
  337. * identity.
  338. *
  339. * @param Net_DNS2_RR $rr the RR object to be used as a prerequisite
  340. *
  341. * @return boolean
  342. * @throws Net_DNS2_Exception
  343. * @access public
  344. *
  345. */
  346. public function checkValueExists(Net_DNS2_RR $rr)
  347. {
  348. $this->_checkName($rr->name);
  349. $rr->ttl = 0;
  350. //
  351. // add the RR to the "prerequisite" section
  352. //
  353. if (!in_array($rr, $this->_packet->answer)) {
  354. $this->_packet->answer[] = $rr;
  355. }
  356. return true;
  357. }
  358. /**
  359. * 2.4.3 - RRset Does Not Exist
  360. *
  361. * No RRs with a specified NAME and TYPE (in the zone and class denoted
  362. * by the Zone Section) can exist.
  363. *
  364. * For this prerequisite, a requestor adds to the section a single RR
  365. * whose NAME and TYPE are equal to that of the RRset whose nonexistence
  366. * is required. The RDLENGTH of this record is zero (0), and RDATA
  367. * field is therefore empty. CLASS must be specified as NONE in order
  368. * to distinguish this condition from a valid RR whose RDLENGTH is
  369. * naturally zero (0) (for example, the NULL RR). TTL must be specified
  370. * as zero (0).
  371. *
  372. * @param string $name the RR name for the prerequisite
  373. * @param string $type the RR type for the prerequisite
  374. *
  375. * @return boolean
  376. * @throws Net_DNS2_Exception
  377. * @access public
  378. *
  379. */
  380. public function checkNotExists($name, $type)
  381. {
  382. $this->_checkName($name);
  383. $class = Net_DNS2_Lookups::$rr_types_id_to_class[
  384. Net_DNS2_Lookups::$rr_types_by_name[$type]
  385. ];
  386. if (!isset($class)) {
  387. throw new Net_DNS2_Exception(
  388. 'unknown or un-supported resource record type: ' . $type,
  389. Net_DNS2_Lookups::E_RR_INVALID
  390. );
  391. }
  392. $rr = new $class;
  393. $rr->name = $name;
  394. $rr->ttl = 0;
  395. $rr->class = 'NONE';
  396. $rr->rdlength = -1;
  397. $rr->rdata = '';
  398. //
  399. // add the RR to the "prerequisite" section
  400. //
  401. if (!in_array($rr, $this->_packet->answer)) {
  402. $this->_packet->answer[] = $rr;
  403. }
  404. return true;
  405. }
  406. /**
  407. * 2.4.4 - Name Is In Use
  408. *
  409. * Name is in use. At least one RR with a specified NAME (in the zone
  410. * and class specified by the Zone Section) must exist. Note that this
  411. * prerequisite is NOT satisfied by empty nonterminals.
  412. *
  413. * For this prerequisite, a requestor adds to the section a single RR
  414. * whose NAME is equal to that of the name whose ownership of an RR is
  415. * required. RDLENGTH is zero and RDATA is therefore empty. CLASS must
  416. * be specified as ANY to differentiate this condition from that of an
  417. * actual RR whose RDLENGTH is naturally zero (0) (e.g., NULL). TYPE
  418. * must be specified as ANY to differentiate this case from that of an
  419. * RRset existence test. TTL is specified as zero (0).
  420. *
  421. * @param string $name the RR name for the prerequisite
  422. *
  423. * @return boolean
  424. * @throws Net_DNS2_Exception
  425. * @access public
  426. *
  427. */
  428. public function checkNameInUse($name)
  429. {
  430. $this->_checkName($name);
  431. //
  432. // the Net_DNS2_RR_ANY class is just an empty stub class used for these
  433. // cases only
  434. //
  435. $rr = new Net_DNS2_RR_ANY;
  436. $rr->name = $name;
  437. $rr->ttl = 0;
  438. $rr->type = 'ANY';
  439. $rr->class = 'ANY';
  440. $rr->rdlength = -1;
  441. $rr->rdata = '';
  442. //
  443. // add the RR to the "prerequisite" section
  444. //
  445. if (!in_array($rr, $this->_packet->answer)) {
  446. $this->_packet->answer[] = $rr;
  447. }
  448. return true;
  449. }
  450. /**
  451. * 2.4.5 - Name Is Not In Use
  452. *
  453. * Name is not in use. No RR of any type is owned by a specified NAME.
  454. * Note that this prerequisite IS satisfied by empty nonterminals.
  455. *
  456. * For this prerequisite, a requestor adds to the section a single RR
  457. * whose NAME is equal to that of the name whose nonownership of any RRs
  458. * is required. RDLENGTH is zero and RDATA is therefore empty. CLASS
  459. * must be specified as NONE. TYPE must be specified as ANY. TTL must
  460. * be specified as zero (0).
  461. *
  462. * @param string $name the RR name for the prerequisite
  463. *
  464. * @return boolean
  465. * @throws Net_DNS2_Exception
  466. * @access public
  467. *
  468. */
  469. public function checkNameNotInUse($name)
  470. {
  471. $this->_checkName($name);
  472. //
  473. // the Net_DNS2_RR_ANY class is just an empty stub class used for these
  474. // cases only
  475. //
  476. $rr = new Net_DNS2_RR_ANY;
  477. $rr->name = $name;
  478. $rr->ttl = 0;
  479. $rr->type = 'ANY';
  480. $rr->class = 'NONE';
  481. $rr->rdlength = -1;
  482. $rr->rdata = '';
  483. //
  484. // add the RR to the "prerequisite" section
  485. //
  486. if (!in_array($rr, $this->_packet->answer)) {
  487. $this->_packet->answer[] = $rr;
  488. }
  489. return true;
  490. }
  491. /**
  492. * returns the current internal packet object.
  493. *
  494. * @return Net_DNS2_Packet_Request
  495. * @access public
  496. #
  497. */
  498. public function packet()
  499. {
  500. //
  501. // take a copy
  502. //
  503. $p = $this->_packet;
  504. //
  505. // check for an authentication method; either TSIG or SIG
  506. //
  507. if ( ($this->auth_signature instanceof Net_DNS2_RR_TSIG)
  508. || ($this->auth_signature instanceof Net_DNS2_RR_SIG)
  509. ) {
  510. $p->additional[] = $this->auth_signature;
  511. }
  512. //
  513. // update the counts
  514. //
  515. $p->header->qdcount = count($p->question);
  516. $p->header->ancount = count($p->answer);
  517. $p->header->nscount = count($p->authority);
  518. $p->header->arcount = count($p->additional);
  519. return $p;
  520. }
  521. /**
  522. * executes the update request with the object informaton
  523. *
  524. * @param Net_DNS2_Packet_Response &$response ref to the response object if required
  525. * @return boolean
  526. * @throws Net_DNS2_Exception
  527. * @access public
  528. *
  529. */
  530. public function update(&$response = null)
  531. {
  532. //
  533. // make sure we have some name servers set
  534. //
  535. $this->checkServers(Net_DNS2::RESOLV_CONF);
  536. //
  537. // check for an authentication method; either TSIG or SIG
  538. //
  539. if ( ($this->auth_signature instanceof Net_DNS2_RR_TSIG)
  540. || ($this->auth_signature instanceof Net_DNS2_RR_SIG)
  541. ) {
  542. $this->_packet->additional[] = $this->auth_signature;
  543. }
  544. //
  545. // update the counts
  546. //
  547. $this->_packet->header->qdcount = count($this->_packet->question);
  548. $this->_packet->header->ancount = count($this->_packet->answer);
  549. $this->_packet->header->nscount = count($this->_packet->authority);
  550. $this->_packet->header->arcount = count($this->_packet->additional);
  551. //
  552. // make sure we have some data to send
  553. //
  554. if ( ($this->_packet->header->qdcount == 0)
  555. || ($this->_packet->header->nscount == 0)
  556. ) {
  557. throw new Net_DNS2_Exception(
  558. 'empty headers- nothing to send!',
  559. Net_DNS2_Lookups::E_PACKET_INVALID
  560. );
  561. }
  562. //
  563. // send the packet and get back the response
  564. //
  565. $response = $this->sendPacket($this->_packet, $this->use_tcp);
  566. //
  567. // clear the internal packet so if we make another request, we don't have
  568. // old data being sent.
  569. //
  570. $this->_packet->reset();
  571. //
  572. // for updates, we just need to know it worked- we don't actualy need to
  573. // return the response object
  574. //
  575. return true;
  576. }
  577. }
  578. /*
  579. * Local variables:
  580. * tab-width: 4
  581. * c-basic-offset: 4
  582. * c-hanging-comment-ender-p: nil
  583. * End:
  584. */
  585. ?>