* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ require_once ('qcEvents/Stream/DNS/Message.php'); require_once ('qcEvents/Stream/DNS/Record/A.php'); require_once ('qcEvents/Stream/DNS/Record/NS.php'); require_once ('qcEvents/Stream/DNS/Record/CNAME.php'); require_once ('qcEvents/Stream/DNS/Record/SOA.php'); require_once ('qcEvents/Stream/DNS/Record/PTR.php'); require_once ('qcEvents/Stream/DNS/Record/MX.php'); require_once ('qcEvents/Stream/DNS/Record/TXT.php'); require_once ('qcEvents/Stream/DNS/Record/AAAA.php'); require_once ('qcEvents/Stream/DNS/Record/SRV.php'); require_once ('qcEvents/Stream/DNS/Record/EDNS.php'); class qcEvents_Stream_DNS_Record { const DEFAULT_TYPE = null; const DEFAULT_CLASS = null; const DEFAULT_TTL = null; /** * Registry for record-classes **/ private static $Records = array ( qcEvents_Stream_DNS_Message::TYPE_A => 'qcEvents_Stream_DNS_Record_A', qcEvents_Stream_DNS_Message::TYPE_NS => 'qcEvents_Stream_DNS_Record_NS', qcEvents_Stream_DNS_Message::TYPE_CNAME => 'qcEvents_Stream_DNS_Record_CNAME', qcEvents_Stream_DNS_Message::TYPE_SOA => 'qcEvents_Stream_DNS_Record_SOA', qcEvents_Stream_DNS_Message::TYPE_PTR => 'qcEvents_Stream_DNS_Record_PTR', qcEvents_Stream_DNS_Message::TYPE_MX => 'qcEvents_Stream_DNS_Record_MX', qcEvents_Stream_DNS_Message::TYPE_TXT => 'qcEvents_Stream_DNS_Record_TXT', qcEvents_Stream_DNS_Message::TYPE_AAAA => 'qcEvents_Stream_DNS_Record_AAAA', qcEvents_Stream_DNS_Message::TYPE_SRV => 'qcEvents_Stream_DNS_Record_SRV', qcEvents_Stream_DNS_Message::TYPE_OPT => 'qcEvents_Stream_DNS_Record_EDNS', ); /** * [QName] The Label that is asked for **/ private $Label = ''; /** * [QType] Type of this DNS-RR **/ private $Type = qcEvents_Stream_DNS_Message::TYPE_ANY; /** * [QClass] Class of this DNS-RR **/ private $Class = qcEvents_Stream_DNS_Message::CLASS_INTERNET; /** * [TTL] Time-to-live of this DNS-RR **/ private $TTL = 0; /** * [RData] Payload of this DNS-RR **/ public $Payload = ''; // {{{ fromString /** * Try to create a new DNS-Record from string * * @param string $Data * @param int $Offset * @parma int $Length (optional) * * @access public * @return qcEvents_Stream_DNS_Record **/ public static function fromString ($Data, &$Offset, $Length = null) { // Check if there is enough data available if ($Length === null) $Length = strlen ($Data); if ($Length - $Offset < 10) return false; // Retrive the label of this record $Label = qcEvents_Stream_DNS_Message::getLabel ($Data, $Offset); // Retrive type, class and TTL $Type = self::parseInt16 ($Data, $Offset); $Class = self::parseInt16 ($Data, $Offset); $TTL = self::parseInt32 ($Data, $Offset); // Retrive the payload $rdLength = self::parseInt16 ($Data, $Offset); $Payload = substr ($Data, $Offset, $rdLength); $pOffset = $Offset; $Offset += $rdLength; // Create a new record if (isset (self::$Records [$Type])) $objClass = self::$Records [$Type]; else $objClass = get_called_class (); $Record = new $objClass ($Label, $TTL, $Type, $Class); // Try to parse the payload $Record->Payload = $Payload; if (!$Record->parsePayload ($Data, $pOffset, $rdLength)) return false; return $Record; } // }}} // {{{ registerRecordClass /** * Register a class for a given record-type * * @param int $Type * @param string $Class * * @access public * @return bool **/ public static function registerRecordClass ($Type, $Class) { // Make sure that this is a child of ourself if (!is_a ($Class, __CLASS__, true)) return false; // Store the classname self::$Records [$Type] = $Class; return true; } // }}} // {{{ __construct /** * Create a new DNS-Record * * @param string $Label (optional) * @paran int $TTL (optional) * @param enum $Type (optional) * @param enum $Class (optional) * * @access friendly * @return void **/ function __construct ($Label = null, $TTL = null, $Type = null, $Class = null) { if ($Type === null) $Type = $this::DEFAULT_TYPE; if ($Class === null) $Class = $this::DEFAULT_CLASS; if ($TTL === null) $TTL = $this::DEFAULT_TTL; if ($Label !== null) $this->setLabel ($Label); if ($Type !== null) $this->setType ($Type); if ($Class !== null) $this->setClass ($Class); if ($TTL !== null) $this->setTTL ($TTL); } // }}} // {{{ getLabel /** * Retrive the label of this record * * @access public * @return string **/ public function getLabel () { return $this->Label; } // }}} // {{{ setLabel /** * Set the label of this record * * @param string $Label * * @access public * @return bool **/ public function setLabel ($Label) { $this->Label = $Label; return true; } // }}} // {{{ getType /** * Retrive the type of this record * * @access public * @return enum **/ public function getType () { return $this->Type; } // }}} // {{{ setType /** * Set the type of this record * * @param enum $Type * * @access public * @return bool **/ public function setType ($Type) { # TODO: Validate the type $this->Type = $Type; return true; } // }}} // {{{ getClass /** * Retrive the class of this record * * @access public * @return enum **/ public function getClass () { return $this->Class; } // }}} protected function getClassName () { switch ($this->Class) { case qcEvents_Stream_DNS_Message::CLASS_INTERNET: return 'IN'; } return $this->Class; } // {{{ setClass /** * Set the class of this record * * @param enum $Class * * @access public * @return bool **/ public function setClass ($Class) { # TODO: Validate the class $this->Class = $Class; return true; } // }}} // {{{ getTTL /** * Retrive the time-to-live of this record * * @access public * @return int **/ public function getTTL () { return $this->TTL; } // }}} // {{{ setTTL /** * Set the TTL of this record * * @param int $TTL * * @access public * @return bool **/ public function setTTL ($TTL) { if (($this->TTL < 0) || ($this->TTL > 0xFFFFFFFF)) return false; $this->TTL = (int)$TTL; return true; } // }}} // {{{ getPayload /** * Retrive the entire payload-blob of this record * * @access public * @return string **/ public function getPayload () { return $this->Payload; } // }}} // {{{ parse /** * Parse binary data into this object * * @param string $Data * @param int $Offset * @param int $Length (optional) * * @access public * @return bool **/ public function parse ($Data, &$Offset, $Length = null) { // Check if there is enough data available if ($Length === null) $Length = strlen ($Data); if ($Length - $Offset < 10) return false; // Retrive the label of this record $this->Label = qcEvents_Stream_DNS_Message::getLabel ($Data, $Offset); // Retrive type, class and TTL $this->Type = self::parseInt16 ($Data, $Offset); $this->Class = self::parseInt16 ($Data, $Offset); $this->TTL = self::parseInt32 ($Data, $Offset); // Retrive the payload $rdLength = self::parseInt16 ($Data, $Offset); $this->Payload = substr ($Data, $Offset, $rdLength); $pOffset = $Offset; $Offset += $rdLength; return $this->parsePayload ($Data, $pOffset, $rdLength); } // }}} // {{{ parseInt16 /** * Read a 16-bit integer from binary * * @param string $Data * @param int $Offset * * @access protected * @return int **/ protected static function parseInt16 ($Data, &$Offset) { return (ord ($Data [$Offset++]) << 8) | ord ($Data [$Offset++]); } // }}} // {{{ parseInt32 /** * Read a 32-bit integer from binary * * @param string $Data * @param int $Offset * * @access protected * @return int **/ protected static function parseInt32 ($Data, &$Offset) { return (ord ($Data [$Offset++]) << 24) | (ord ($Data [$Offset++]) << 16) | (ord ($Data [$Offset++]) << 8) | ord ($Data [$Offset++]); } // }}} // {{{ parsePayload /** * Parse a given payload * * @param string $Data * @param int $Offset (optional) * @param int $Length (optional) * * @access public * @return bool **/ public function parsePayload ($Data, $Offset = 0, $Length = null) { if ($Length === null) $Length = strlen ($Data) - $Offset; // Handle the payload switch ($this->Type) { #case qcEvents_Stream_DNS_Message::TYPE_WKS: # TODO: Address <8-bit protocol> # $this->Address = ord ($this->Payload [0]) . '.' . ord ($this->Payload [1]) . '.' . ord ($this->Payload [2]) . '.' . ord ($this->Payload [3]); # break; // Hostnames case qcEvents_Stream_DNS_Message::TYPE_MB: case qcEvents_Stream_DNS_Message::TYPE_MD: case qcEvents_Stream_DNS_Message::TYPE_MF: case qcEvents_Stream_DNS_Message::TYPE_MG: case qcEvents_Stream_DNS_Message::TYPE_MR: $this->Hostname = qcEvents_Stream_DNS_Message::getLabel ($Data, $Offset); break; // Two hostnames case qcEvents_Stream_DNS_Message::TYPE_MINFO: #$this->Mailbox = qcEvents_Stream_DNS_Message::getLabel ($Data, $Offset); #$this->errorMailbox = qcEvents_Stream_DNS_Message::getLabel ($Data, $Offset); #break; // Specials case qcEvents_Stream_DNS_Message::TYPE_HINFO: // CPU / OS Character-Strings } return true; } // }}} // {{{ toString /** * Convert this question into a string * * @param int $Offset * @param array &$Labels * * @access public * @return string **/ public function toString ($Offset, &$Labels) { // Create the record-header $Data = qcEvents_Stream_DNS_Message::setLabel ($this->Label, $Offset, $Labels) . self::buildInt16 ($this->Type) . self::buildInt16 ($this->Class) . self::buildInt32 ($this->TTL); // Retrive the payload if (($Payload = $this->buildPayload ($Offset + strlen ($Data) + 2, $Labels)) === false) return false; // Append the payload $Data .= self::buildInt16 (strlen ($Payload)) . $Payload; return $Data; } // }}} // {{{ buildPayload /** * Retrive the payload of this record * * @param int $Offset * @param array &$Labels * * @access public * @return string **/ public function buildPayload ($Offset, &$Labels) { return $this->Payload; } // }}} // {{{ buildInt16 /** * Create a binary representation of a 16-bit integer * * @param int $Value * * @access protected * @return string **/ protected function buildInt16 ($Value) { return chr (($Value & 0xFF00) >> 8) . chr ($Value & 0xFF); } // }}} // {{{ buildInt32 /** * Create a binary representation of a 32-bit integer * * @param int $Value * * @access protected * @return string **/ protected function buildInt32 ($Value) { return chr (($Value & 0xFF000000) >> 24) . chr (($Value & 0x00FF0000) >> 16) . chr (($Value & 0x0000FF00) >> 8) . chr ($Value & 0x000000FF); } // }}} } ?>