From efe1be95d550a3c9a7dfa189d2bb678a76a9664a Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 14 Jan 2019 14:45:37 -0500 Subject: [PATCH] pull email validator into repo --- signup/email/Net/DNS2.php | 9861 +++++++++++++++++++++++++++++++++++++ signup/email/ipaddr.php | 210 + signup/email/smtp.php | 1519 ++++++ signup/email/utf8.php | 208 + signup/signup-handler.php | 6 +- 5 files changed, 11800 insertions(+), 4 deletions(-) create mode 100644 signup/email/Net/DNS2.php create mode 100644 signup/email/ipaddr.php create mode 100644 signup/email/smtp.php create mode 100644 signup/email/utf8.php diff --git a/signup/email/Net/DNS2.php b/signup/email/Net/DNS2.php new file mode 100644 index 0000000..83074e9 --- /dev/null +++ b/signup/email/Net/DNS2.php @@ -0,0 +1,9861 @@ + array(), 'tcp' => array()); + + protected $sockets_enabled = false; + + protected $auth_signature = null; + + protected $cache = null; + + protected $use_cache = false; + + public function __construct(array $options = null) + { + // + + // + + // + if ( (extension_loaded('sockets') == true) && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') ) { + + $this->sockets_enabled = true; + } + + // + + // + if (!empty($options)) { + + foreach ($options as $key => $value) { + + if ($key == 'nameservers') { + + $this->setServers($value); + } else { + + $this->$key = $value; + } + } + } + + // + + // + switch($this->cache_type) { + case 'shared': + if (extension_loaded('shmop')) { + + $this->cache = new Net_DNS2_Cache_Shm; + $this->use_cache = true; + } else { + + throw new Net_DNS2_Exception( + 'shmop library is not available for cache', + Net_DNS2_Lookups::E_CACHE_SHM_UNAVAIL + ); + } + break; + case 'file': + + $this->cache = new Net_DNS2_Cache_File; + $this->use_cache = true; + + break; + case 'none': + $this->use_cache = false; + break; + default: + + throw new Net_DNS2_Exception( + 'un-supported cache type: ' . $this->cache_type, + Net_DNS2_Lookups::E_CACHE_UNSUPPORTED + ); + } + } + + static public function autoload($name) + { + // + + // + if (strncmp($name, 'Net_DNS2', 8) == 0) { + + include str_replace('_', '/', $name) . '.php'; + } + + return; + } + + public function setServers($nameservers) + { + // + + // + + // + if (is_array($nameservers)) { + + $this->nameservers = $nameservers; + + } else { + + // + + // + $ns = array(); + + // + + // + if (is_readable($nameservers) === true) { + + $data = file_get_contents($nameservers); + if ($data === false) { + throw new Net_DNS2_Exception( + 'failed to read contents of file: ' . $nameservers, + Net_DNS2_Lookups::E_NS_INVALID_FILE + ); + } + + $lines = explode("\n", $data); + + foreach ($lines as $line) { + + $line = trim($line); + + // + + // + if ( (strlen($line) == 0) + || ($line[0] == '#') + || ($line[0] == ';') + ) { + continue; + } + + // + + // + if (strpos($line, ' ') === false) { + continue; + } + + list($key, $value) = preg_split('/\s+/', $line, 2); + + $key = trim(strtolower($key)); + $value = trim(strtolower($value)); + + switch($key) { + case 'nameserver': + + // + + // + if ( (self::isIPv4($value) == true) + || (self::isIPv6($value) == true) + ) { + + $ns[] = $value; + } else { + + throw new Net_DNS2_Exception( + 'invalid nameserver entry: ' . $value, + Net_DNS2_Lookups::E_NS_INVALID_ENTRY + ); + } + break; + + case 'domain': + $this->domain = $value; + break; + + case 'search': + $this->search_list = preg_split('/\s+/', $value); + break; + + case 'options': + $this->parseOptions($value); + break; + + default: + ; + } + } + + // + + // + if ( (strlen($this->domain) == 0) + && (count($this->search_list) > 0) + ) { + $this->domain = $this->search_list[0]; + } + + } else { + throw new Net_DNS2_Exception( + 'resolver file file provided is not readable: ' . $nameservers, + Net_DNS2_Lookups::E_NS_INVALID_FILE + ); + } + + // + + // + if (count($ns) > 0) { + $this->nameservers = $ns; + } + } + + // + + // + $this->nameservers = array_unique($this->nameservers); + + // + + // + $this->checkServers(); + + return true; + } + + private function parseOptions($value) + { + // + + // + if ( ($this->use_resolv_options == false) || (strlen($value) == 0) ) { + + return true; + } + + $options = preg_split('/\s+/', strtolower($value)); + + foreach ($options as $option) { + + // + + // + if ( (strncmp($option, 'timeout', 7) == 0) && (strpos($option, ':') !== false) ) { + + list($key, $val) = explode(':', $option); + + if ( ($val > 0) && ($val <= 30) ) { + + $this->timeout = $val; + } + + // + + // + } else if (strncmp($option, 'rotate', 6) == 0) { + + $this->ns_random = true; + } + } + + return true; + } + + protected function checkServers($default = null) + { + if (empty($this->nameservers)) { + + if (isset($default)) { + + $this->setServers($default); + } else { + + throw new Net_DNS2_Exception( + 'empty name servers list; you must provide a list of name '. + 'servers, or the path to a resolv.conf file.', + Net_DNS2_Lookups::E_NS_INVALID_ENTRY + ); + } + } + + return true; + } + + public function signTSIG( + $keyname, $signature = '', $algorithm = Net_DNS2_RR_TSIG::HMAC_MD5 + ) { + // + + // + if ($keyname instanceof Net_DNS2_RR_TSIG) { + + $this->auth_signature = $keyname; + + } else { + + // + + // + $this->auth_signature = Net_DNS2_RR::fromString( + strtolower(trim($keyname)) . + ' TSIG '. $signature + ); + + // + + // + $this->auth_signature->algorithm = $algorithm; + } + + return true; + } + + public function signSIG0($filename) + { + // + + // + if (extension_loaded('openssl') === false) { + + throw new Net_DNS2_Exception( + 'the OpenSSL extension is required to use SIG(0).', + Net_DNS2_Lookups::E_OPENSSL_UNAVAIL + ); + } + + // + + // + if ($filename instanceof Net_DNS2_RR_SIG) { + + $this->auth_signature = $filename; + + } else { + + // + + // + $private = new Net_DNS2_PrivateKey($filename); + + // + + // + $this->auth_signature = new Net_DNS2_RR_SIG(); + + // + + // + $this->auth_signature->name = $private->signname; + $this->auth_signature->ttl = 0; + $this->auth_signature->class = 'ANY'; + + // + + // + $this->auth_signature->algorithm = $private->algorithm; + $this->auth_signature->keytag = $private->keytag; + $this->auth_signature->signname = $private->signname; + + // + + // + $this->auth_signature->typecovered = 'SIG0'; + $this->auth_signature->labels = 0; + $this->auth_signature->origttl = 0; + + // + + // + $t = time(); + + $this->auth_signature->sigincep = gmdate('YmdHis', $t); + $this->auth_signature->sigexp = gmdate('YmdHis', $t + 500); + + // + + // + $this->auth_signature->private_key = $private; + } + + // + + // + switch($this->auth_signature->algorithm) { + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSA: + break; + default: + throw new Net_DNS2_Exception( + 'only asymmetric algorithms work with SIG(0)!', + Net_DNS2_Lookups::E_OPENSSL_INV_ALGO + ); + } + + return true; + } + + public function cacheable($_type) + { + switch($_type) { + case 'AXFR': + case 'OPT': + return false; + } + + return true; + } + + public static function expandUint32($_int) + { + if ( ($_int < 0) && (PHP_INT_MAX == 2147483647) ) { + return sprintf('%u', $_int); + } else { + return $_int; + } + } + + public static function isIPv4($_address) + { + // + + // + if (extension_loaded('filter') == true) { + + if (filter_var($_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) == false) { + return false; + } + } else { + + // + + // + if (inet_pton($_address) === false) { + return false; + } + + // + + // + if (preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $_address) == 0) { + return false; + } + } + + return true; + } + + public static function isIPv6($_address) + { + // + + // + if (extension_loaded('filter') == true) { + if (filter_var($_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) == false) { + return false; + } + } else { + + // + + // + if (inet_pton($_address) === false) { + return false; + } + + // + + // + if (preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $_address) == 1) { + return false; + } + } + + return true; + } + + public static function expandIPv6($_address) + { + if (strpos($_address, '::') !== false) { + + $part = explode('::', $_address); + $part[0] = explode(':', $part[0]); + $part[1] = explode(':', $part[1]); + + $missing = array(); + + $x = (8 - (count($part[0]) + count($part[1]))); + for ($i = 0; $i < $x; $i++) { + + array_push($missing, '0000'); + } + + $missing = array_merge($part[0], $missing); + $part = array_merge($missing, $part[1]); + + } else { + + $part = explode(':', $_address); + } + + foreach ($part as &$p) { + while (strlen($p) < 4) { + $p = '0' . $p; + } + } + + unset($p); + + $result = implode(':', $part); + + if (strlen($result) == 39) { + return $result; + } else { + return false; + } + } + + protected function sendPacket(Net_DNS2_Packet $request, $use_tcp) + { + // + + // + $data = $request->get(); + if (strlen($data) < Net_DNS2_Lookups::DNS_HEADER_SIZE) { + + throw new Net_DNS2_Exception( + 'invalid or empty packet for sending!', + Net_DNS2_Lookups::E_PACKET_INVALID, + null, + $request + ); + } + + reset($this->nameservers); + + // + + // + if ($this->ns_random == true) { + + shuffle($this->nameservers); + } + + // + + // + $response = null; + $ns = ''; + + while (1) { + + // + + // + $ns = each($this->nameservers); + if ($ns === false) { + + if (is_null($this->last_exception) == false) { + + throw $this->last_exception; + } else { + + throw new Net_DNS2_Exception( + 'every name server provided has failed', + Net_DNS2_Lookups::E_NS_FAILED + ); + } + } + + $ns = $ns[1]; + + // + + // + $max_udp_size = Net_DNS2_Lookups::DNS_MAX_UDP_SIZE; + if ($this->dnssec == true) + { + $max_udp_size = $this->dnssec_payload_size; + } + + if ( ($use_tcp == true) || (strlen($data) > $max_udp_size) ) { + + try + { + $response = $this->sendTCPRequest($ns, $data, ($request->question[0]->qtype == 'AXFR') ? true : false); + + } catch(Net_DNS2_Exception $e) { + + $this->last_exception = $e; + $this->last_exception_list[$ns] = $e; + + continue; + } + + // + + // + } else { + + try + { + $response = $this->sendUDPRequest($ns, $data); + + // + + // + if ($response->header->tc == 1) { + + $response = $this->sendTCPRequest($ns, $data); + } + + } catch(Net_DNS2_Exception $e) { + + $this->last_exception = $e; + $this->last_exception_list[$ns] = $e; + + continue; + } + } + + // + + // + if ($request->header->id != $response->header->id) { + + $this->last_exception = new Net_DNS2_Exception( + + 'invalid header: the request and response id do not match.', + Net_DNS2_Lookups::E_HEADER_INVALID, + null, + $request, + $response + ); + + $this->last_exception_list[$ns] = $this->last_exception; + continue; + } + + // + + // + + // + if ($response->header->qr != Net_DNS2_Lookups::QR_RESPONSE) { + + $this->last_exception = new Net_DNS2_Exception( + + 'invalid header: the response provided is not a response packet.', + Net_DNS2_Lookups::E_HEADER_INVALID, + null, + $request, + $response + ); + + $this->last_exception_list[$ns] = $this->last_exception; + continue; + } + + // + + // + if ($response->header->rcode != Net_DNS2_Lookups::RCODE_NOERROR) { + + $this->last_exception = new Net_DNS2_Exception( + + 'DNS request failed: ' . + Net_DNS2_Lookups::$result_code_messages[$response->header->rcode], + $response->header->rcode, + null, + $request, + $response + ); + + $this->last_exception_list[$ns] = $this->last_exception; + continue; + } + + break; + } + + return $response; + } + + private function sendTCPRequest($_ns, $_data, $_axfr = false) + { + // + + // + $start_time = microtime(true); + + // + + // + if ( (!isset($this->sock['tcp'][$_ns])) + || (!($this->sock['tcp'][$_ns] instanceof Net_DNS2_Socket)) + ) { + + // + + // + if ($this->sockets_enabled === true) { + + $this->sock['tcp'][$_ns] = new Net_DNS2_Socket_Sockets( + Net_DNS2_Socket::SOCK_STREAM, $_ns, $this->dns_port, $this->timeout + ); + + // + + // + } else { + + $this->sock['tcp'][$_ns] = new Net_DNS2_Socket_Streams( + Net_DNS2_Socket::SOCK_STREAM, $_ns, $this->dns_port, $this->timeout + ); + } + + // + + // + if (strlen($this->local_host) > 0) { + + $this->sock['tcp'][$_ns]->bindAddress( + $this->local_host, $this->local_port + ); + } + + // + + // + if ($this->sock['tcp'][$_ns]->open() === false) { + + throw new Net_DNS2_Exception( + $this->sock['tcp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + } + + // + + // + if ($this->sock['tcp'][$_ns]->write($_data) === false) { + + throw new Net_DNS2_Exception( + $this->sock['tcp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + + // + + // + $size = 0; + $result = null; + $response = null; + + // + + // + if ($_axfr == true) { + + $soa_count = 0; + + while (1) { + + // + + // + $result = $this->sock['tcp'][$_ns]->read($size, ($this->dnssec == true) ? $this->dnssec_payload_size : Net_DNS2_Lookups::DNS_MAX_UDP_SIZE); + if ( ($result === false) || ($size < Net_DNS2_Lookups::DNS_HEADER_SIZE) ) { + + throw new Net_DNS2_Exception( + $this->sock['tcp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + + // + + // + $chunk = new Net_DNS2_Packet_Response($result, $size); + + // + + // + if (is_null($response) == true) { + + $response = clone $chunk; + + // + + // + if ($response->header->rcode != Net_DNS2_Lookups::RCODE_NOERROR) { + break; + } + + // + + // + foreach ($response->answer as $index => $rr) { + + // + + // + if ($rr->type == 'SOA') { + $soa_count++; + } + } + + // + + // + if ($soa_count >= 2) { + break; + } else { + continue; + } + + } else { + + // + + // + foreach ($chunk->answer as $index => $rr) { + + // + + // + if ($rr->type == 'SOA') { + $soa_count++; + } + + // + + // + $response->answer[] = $rr; + } + + // + + // + if ($soa_count >= 2) { + break; + } + } + } + + // + + // + } else { + + $result = $this->sock['tcp'][$_ns]->read($size, ($this->dnssec == true) ? $this->dnssec_payload_size : Net_DNS2_Lookups::DNS_MAX_UDP_SIZE); + if ( ($result === false) || ($size < Net_DNS2_Lookups::DNS_HEADER_SIZE) ) { + + throw new Net_DNS2_Exception( + $this->sock['tcp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + + // + + // + $response = new Net_DNS2_Packet_Response($result, $size); + } + + // + + // + $response->response_time = microtime(true) - $start_time; + + // + + // + $response->answer_from = $_ns; + $response->answer_socket_type = Net_DNS2_Socket::SOCK_STREAM; + + // + + // + return $response; + } + + private function sendUDPRequest($_ns, $_data) + { + // + + // + $start_time = microtime(true); + + // + + // + if ( (!isset($this->sock['udp'][$_ns])) + || (!($this->sock['udp'][$_ns] instanceof Net_DNS2_Socket)) + ) { + + // + + // + if ($this->sockets_enabled === true) { + + $this->sock['udp'][$_ns] = new Net_DNS2_Socket_Sockets( + Net_DNS2_Socket::SOCK_DGRAM, $_ns, $this->dns_port, $this->timeout + ); + + // + + // + } else { + + $this->sock['udp'][$_ns] = new Net_DNS2_Socket_Streams( + Net_DNS2_Socket::SOCK_DGRAM, $_ns, $this->dns_port, $this->timeout + ); + } + + // + + // + if (strlen($this->local_host) > 0) { + + $this->sock['udp'][$_ns]->bindAddress( + $this->local_host, $this->local_port + ); + } + + // + + // + if ($this->sock['udp'][$_ns]->open() === false) { + + throw new Net_DNS2_Exception( + $this->sock['udp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + } + + // + + // + if ($this->sock['udp'][$_ns]->write($_data) === false) { + + throw new Net_DNS2_Exception( + $this->sock['udp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + + // + + // + $size = 0; + + $result = $this->sock['udp'][$_ns]->read($size, ($this->dnssec == true) ? $this->dnssec_payload_size : Net_DNS2_Lookups::DNS_MAX_UDP_SIZE); + if (( $result === false) || ($size < Net_DNS2_Lookups::DNS_HEADER_SIZE)) { + + throw new Net_DNS2_Exception( + $this->sock['udp'][$_ns]->last_error, Net_DNS2_Lookups::E_NS_SOCKET_FAILED + ); + } + + // + + // + $response = new Net_DNS2_Packet_Response($result, $size); + + // + + // + $response->response_time = microtime(true) - $start_time; + + // + + // + $response->answer_from = $_ns; + $response->answer_socket_type = Net_DNS2_Socket::SOCK_DGRAM; + + // + + // + return $response; + } +} + +?> $max) { + $max = $val; + } + + $bm[$current_window][$val] = 1; + $bm[$current_window]['length'] = ceil(($max + 1) / 8); + } + + $output = ''; + + foreach ($bm as $window => $bitdata) { + + $bitstr = ''; + + for ($i=0; $i<$bm[$window]['length'] * 8; $i++) { + if (isset($bm[$window][$i])) { + $bitstr .= '1'; + } else { + $bitstr .= '0'; + } + } + + $output .= pack('CC', $window, $bm[$window]['length']); + $output .= pack('H*', self::bigBaseConvert($bitstr)); + } + + return $output; + } + + public static function bigBaseConvert($number) + { + $result = ''; + + $bin = substr(chunk_split(strrev($number), 4, '-'), 0, -1); + $temp = preg_split('[-]', $bin, -1, PREG_SPLIT_DELIM_CAPTURE); + + for ($i = count($temp)-1;$i >= 0;$i--) { + + $result = $result . base_convert(strrev($temp[$i]), 2, 16); + } + + return strtoupper($result); + } +} + +?>cache_data[$key]); + } + + public function get($key) + { + if (isset($this->cache_data[$key])) { + + if ($this->cache_serializer == 'json') { + return json_decode($this->cache_data[$key]['object']); + } else { + return unserialize($this->cache_data[$key]['object']); + } + } else { + + return false; + } + } + + public function put($key, $data) + { + $ttl = 86400 * 365; + + // + + // + $data->rdata = ''; + $data->rdlength = 0; + + // + + // + + // + foreach ($data->answer as $index => $rr) { + + if ($rr->ttl < $ttl) { + $ttl = $rr->ttl; + } + + $rr->rdata = ''; + $rr->rdlength = 0; + } + foreach ($data->authority as $index => $rr) { + + if ($rr->ttl < $ttl) { + $ttl = $rr->ttl; + } + + $rr->rdata = ''; + $rr->rdlength = 0; + } + foreach ($data->additional as $index => $rr) { + + if ($rr->ttl < $ttl) { + $ttl = $rr->ttl; + } + + $rr->rdata = ''; + $rr->rdlength = 0; + } + + $this->cache_data[$key] = array( + + 'cache_date' => time(), + 'ttl' => $ttl + ); + + if ($this->cache_serializer == 'json') { + $this->cache_data[$key]['object'] = json_encode($data); + } else { + $this->cache_data[$key]['object'] = serialize($data); + } + } + + protected function clean() + { + if (count($this->cache_data) > 0) { + + // + + // + $now = time(); + + foreach ($this->cache_data as $key => $data) { + + $diff = $now - $data['cache_date']; + + if ($data['ttl'] <= $diff) { + + unset($this->cache_data[$key]); + } else { + + $this->cache_data[$key]['ttl'] -= $diff; + $this->cache_data[$key]['cache_date'] = $now; + } + } + } + } + + protected function resize() + { + if (count($this->cache_data) > 0) { + + // + + // + if ($this->cache_serializer == 'json') { + $cache = json_encode($this->cache_data); + } else { + $cache = serialize($this->cache_data); + } + + // + + // + if (strlen($cache) > $this->cache_size) { + + while (strlen($cache) > $this->cache_size) { + + // + + // + $smallest_ttl = time(); + $smallest_key = null; + + foreach ($this->cache_data as $key => $data) { + + if ($data['ttl'] < $smallest_ttl) { + + $smallest_ttl = $data['ttl']; + $smallest_key = $key; + } + } + + // + + // + unset($this->cache_data[$smallest_key]); + + // + + // + if ($this->cache_serializer == 'json') { + $cache = json_encode($this->cache_data); + } else { + $cache = serialize($this->cache_data); + } + } + } + + if ( ($cache == 'a:0:{}') || ($cache == '{}') ) { + return null; + } else { + return $cache; + } + } + + return null; + } +}; + +?>_request = $request; + $this->_response = $response; + + // + + // + + // + + // + if (version_compare(PHP_VERSION, '5.3.0', '>=') == true) { + + parent::__construct($message, $code, $previous); + } else { + + parent::__construct($message, $code); + } + } + + public function getRequest() + { + return $this->_request; + } + + public function getResponse() + { + return $this->_response; + } +} + +?>set($packet); + } else { + + $this->id = $this->nextPacketId(); + $this->qr = Net_DNS2_Lookups::QR_QUERY; + $this->opcode = Net_DNS2_Lookups::OPCODE_QUERY; + $this->aa = 0; + $this->tc = 0; + $this->rd = 1; + $this->ra = 0; + $this->z = 0; + $this->ad = 0; + $this->cd = 0; + $this->rcode = Net_DNS2_Lookups::RCODE_NOERROR; + $this->qdcount = 1; + $this->ancount = 0; + $this->nscount = 0; + $this->arcount = 0; + } + } + + public function nextPacketId() + { + if (++Net_DNS2_Lookups::$next_packet_id > 65535) { + + Net_DNS2_Lookups::$next_packet_id = 1; + } + + return Net_DNS2_Lookups::$next_packet_id; + } + + public function __toString() + { + $output = ";;\n;; Header:\n"; + + $output .= ";;\t id = " . $this->id . "\n"; + $output .= ";;\t qr = " . $this->qr . "\n"; + $output .= ";;\t opcode = " . $this->opcode . "\n"; + $output .= ";;\t aa = " . $this->aa . "\n"; + $output .= ";;\t tc = " . $this->tc . "\n"; + $output .= ";;\t rd = " . $this->rd . "\n"; + $output .= ";;\t ra = " . $this->ra . "\n"; + $output .= ";;\t z = " . $this->z . "\n"; + $output .= ";;\t ad = " . $this->ad . "\n"; + $output .= ";;\t cd = " . $this->cd . "\n"; + $output .= ";;\t rcode = " . $this->rcode . "\n"; + $output .= ";;\t qdcount = " . $this->qdcount . "\n"; + $output .= ";;\t ancount = " . $this->ancount . "\n"; + $output .= ";;\t nscount = " . $this->nscount . "\n"; + $output .= ";;\t arcount = " . $this->arcount . "\n"; + + return $output; + } + + public function set(Net_DNS2_Packet &$packet) + { + // + + // + if ($packet->rdlength < Net_DNS2_Lookups::DNS_HEADER_SIZE) { + + throw new Net_DNS2_Exception( + 'invalid header data provided; to small', + Net_DNS2_Lookups::E_HEADER_INVALID + ); + } + + $offset = 0; + + // + + // + $this->id = ord($packet->rdata[$offset]) << 8 | + ord($packet->rdata[++$offset]); + + ++$offset; + $this->qr = (ord($packet->rdata[$offset]) >> 7) & 0x1; + $this->opcode = (ord($packet->rdata[$offset]) >> 3) & 0xf; + $this->aa = (ord($packet->rdata[$offset]) >> 2) & 0x1; + $this->tc = (ord($packet->rdata[$offset]) >> 1) & 0x1; + $this->rd = ord($packet->rdata[$offset]) & 0x1; + + ++$offset; + $this->ra = (ord($packet->rdata[$offset]) >> 7) & 0x1; + $this->z = (ord($packet->rdata[$offset]) >> 6) & 0x1; + $this->ad = (ord($packet->rdata[$offset]) >> 5) & 0x1; + $this->cd = (ord($packet->rdata[$offset]) >> 4) & 0x1; + $this->rcode = ord($packet->rdata[$offset]) & 0xf; + + $this->qdcount = ord($packet->rdata[++$offset]) << 8 | + ord($packet->rdata[++$offset]); + $this->ancount = ord($packet->rdata[++$offset]) << 8 | + ord($packet->rdata[++$offset]); + $this->nscount = ord($packet->rdata[++$offset]) << 8 | + ord($packet->rdata[++$offset]); + $this->arcount = ord($packet->rdata[++$offset]) << 8 | + ord($packet->rdata[++$offset]); + + // + + // + $packet->offset += Net_DNS2_Lookups::DNS_HEADER_SIZE; + + return true; + } + + public function get(Net_DNS2_Packet &$packet) + { + $data = pack('n', $this->id) . + chr( + ($this->qr << 7) | ($this->opcode << 3) | + ($this->aa << 2) | ($this->tc << 1) | ($this->rd) + ) . + chr( + ($this->ra << 7) | ($this->ad << 5) | ($this->cd << 4) | $this->rcode + ) . + chr($this->qdcount << 8) . chr($this->qdcount) . + chr($this->ancount << 8) . chr($this->ancount) . + chr($this->nscount << 8) . chr($this->nscount) . + chr($this->arcount << 8) . chr($this->arcount); + + $packet->offset += Net_DNS2_Lookups::DNS_HEADER_SIZE; + + return $data; + } +} + +?> 0, + 'A' => 1, + 'NS' => 2, + 'MD' => 3, + 'MF' => 4, + 'CNAME' => 5, + 'SOA' => 6, + 'MB' => 7, + 'MG' => 8, + 'MR' => 9, + 'NULL' => 10, + 'WKS' => 11, + 'PTR' => 12, + 'HINFO' => 13, + 'MINFO' => 14, + 'MX' => 15, + 'TXT' => 16, + 'RP' => 17, + 'AFSDB' => 18, + 'X25' => 19, + 'ISDN' => 20, + 'RT' => 21, + 'NSAP' => 22, + 'NSAP_PTR' => 23, + 'SIG' => 24, + 'KEY' => 25, + 'PX' => 26, + 'GPOS' => 27, + 'AAAA' => 28, + 'LOC' => 29, + 'NXT' => 30, + 'EID' => 31, + 'NIMLOC' => 32, + 'SRV' => 33, + 'ATMA' => 34, + 'NAPTR' => 35, + 'KX' => 36, + 'CERT' => 37, + 'A6' => 38, + 'DNAME' => 39, + 'SINK' => 40, + 'OPT' => 41, + 'APL' => 42, + 'DS' => 43, + 'SSHFP' => 44, + 'IPSECKEY' => 45, + 'RRSIG' => 46, + 'NSEC' => 47, + 'DNSKEY' => 48, + 'DHCID' => 49, + 'NSEC3' => 50, + 'NSEC3PARAM' => 51, + 'TLSA' => 52, + + 'HIP' => 55, + 'NINFO' => 56, + 'RKEY' => 57, + 'TALINK' => 58, // + 'CDS' => 59, + 'CDNSKEY' => 60, + 'OPENPGPKEY' => 61, + 'CSYNC' => 62, + + 'SPF' => 99, + 'UINFO' => 100, + 'UID' => 101, + 'GID' => 102, + 'UNSPEC' => 103, + 'NID' => 104, + 'L32' => 105, + 'L64' => 106, + 'LP' => 107, + 'EUI48' => 108, + 'EUI64' => 109, + + 'TKEY' => 249, + 'TSIG' => 250, + 'IXFR' => 251, + 'AXFR' => 252, + 'MAILB' => 253, + 'MAILA' => 254, + 'ANY' => 255, + 'URI' => 256, + 'CAA' => 257, + + 'TA' => 32768, + 'DLV' => 32769 + ); + + public static $rr_qtypes_by_id = array(); + public static $rr_qtypes_by_name = array( + + 'IXFR' => 251, + 'AXFR' => 252, + 'MAILB' => 253, + 'MAILA' => 254, + 'ANY' => 255 + ); + + public static $rr_metatypes_by_id = array(); + public static $rr_metatypes_by_name = array( + + 'OPT' => 41, + 'TKEY' => 249, + 'TSIG' => 250 + ); + + public static $rr_types_class_to_id = array(); + public static $rr_types_id_to_class = array( + + 1 => 'Net_DNS2_RR_A', + 2 => 'Net_DNS2_RR_NS', + 5 => 'Net_DNS2_RR_CNAME', + 6 => 'Net_DNS2_RR_SOA', + 11 => 'Net_DNS2_RR_WKS', + 12 => 'Net_DNS2_RR_PTR', + 13 => 'Net_DNS2_RR_HINFO', + 15 => 'Net_DNS2_RR_MX', + 16 => 'Net_DNS2_RR_TXT', + 17 => 'Net_DNS2_RR_RP', + 18 => 'Net_DNS2_RR_AFSDB', + 19 => 'Net_DNS2_RR_X25', + 20 => 'Net_DNS2_RR_ISDN', + 21 => 'Net_DNS2_RR_RT', + 22 => 'Net_DNS2_RR_NSAP', + 24 => 'Net_DNS2_RR_SIG', + 25 => 'Net_DNS2_RR_KEY', + 26 => 'Net_DNS2_RR_PX', + 28 => 'Net_DNS2_RR_AAAA', + 29 => 'Net_DNS2_RR_LOC', + 31 => 'Net_DNS2_RR_EID', + 32 => 'Net_DNS2_RR_NIMLOC', + 33 => 'Net_DNS2_RR_SRV', + 34 => 'Net_DNS2_RR_ATMA', + 35 => 'Net_DNS2_RR_NAPTR', + 36 => 'Net_DNS2_RR_KX', + 37 => 'Net_DNS2_RR_CERT', + 39 => 'Net_DNS2_RR_DNAME', + 41 => 'Net_DNS2_RR_OPT', + 42 => 'Net_DNS2_RR_APL', + 43 => 'Net_DNS2_RR_DS', + 44 => 'Net_DNS2_RR_SSHFP', + 45 => 'Net_DNS2_RR_IPSECKEY', + 46 => 'Net_DNS2_RR_RRSIG', + 47 => 'Net_DNS2_RR_NSEC', + 48 => 'Net_DNS2_RR_DNSKEY', + 49 => 'Net_DNS2_RR_DHCID', + 50 => 'Net_DNS2_RR_NSEC3', + 51 => 'Net_DNS2_RR_NSEC3PARAM', + 52 => 'Net_DNS2_RR_TLSA', + 55 => 'Net_DNS2_RR_HIP', + 58 => 'Net_DNS2_RR_TALINK', + 59 => 'Net_DNS2_RR_CDS', + 60 => 'Net_DNS2_RR_CDNSKEY', + 61 => 'Net_DNS2_RR_OPENPGPKEY', + 62 => 'Net_DNS2_RR_CSYNC', + 99 => 'Net_DNS2_RR_SPF', + 104 => 'Net_DNS2_RR_NID', + 105 => 'Net_DNS2_RR_L32', + 106 => 'Net_DNS2_RR_L64', + 107 => 'Net_DNS2_RR_LP', + 108 => 'Net_DNS2_RR_EUI48', + 109 => 'Net_DNS2_RR_EUI64', + + 249 => 'Net_DNS2_RR_TKEY', + 250 => 'Net_DNS2_RR_TSIG', + + 255 => 'Net_DNS2_RR_ANY', + 256 => 'Net_DNS2_RR_URI', + 257 => 'Net_DNS2_RR_CAA', + 32768 => 'Net_DNS2_RR_TA', + 32769 => 'Net_DNS2_RR_DLV' + ); + + public static $classes_by_id = array(); + public static $classes_by_name = array( + + 'IN' => self::RR_CLASS_IN, + 'CH' => self::RR_CLASS_CH, + 'HS' => self::RR_CLASS_HS, + 'NONE' => self::RR_CLASS_NONE, + 'ANY' => self::RR_CLASS_ANY + ); + + public static $result_code_messages = array( + + self::RCODE_NOERROR => 'The request completed successfully.', + self::RCODE_FORMERR => 'The name server was unable to interpret the query.', + self::RCODE_SERVFAIL => 'The name server was unable to process this query due to a problem with the name server.', + self::RCODE_NXDOMAIN => 'The domain name referenced in the query does not exist.', + self::RCODE_NOTIMP => 'The name server does not support the requested kind of query.', + self::RCODE_REFUSED => 'The name server refuses to perform the specified operation for policy reasons.', + self::RCODE_YXDOMAIN => 'Name Exists when it should not.', + self::RCODE_YXRRSET => 'RR Set Exists when it should not.', + self::RCODE_NXRRSET => 'RR Set that should exist does not.', + self::RCODE_NOTAUTH => 'Server Not Authoritative for zone.', + self::RCODE_NOTZONE => 'Name not contained in zone.', + + self::RCODE_BADSIG => 'TSIG Signature Failure.', + self::RCODE_BADKEY => 'Key not recognized.', + self::RCODE_BADTIME => 'Signature out of time window.', + self::RCODE_BADMODE => 'Bad TKEY Mode.', + self::RCODE_BADNAME => 'Duplicate key name.', + self::RCODE_BADALG => 'Algorithm not supported.', + self::RCODE_BADTRUNC => 'Bad truncation.' + ); + + public static $algorithm_name_to_id = array(); + public static $algorithm_id_to_name = array( + + self::DNSSEC_ALGORITHM_RES => 'RES', + self::DNSSEC_ALGORITHM_RSAMD5 => 'RSAMD5', + self::DNSSEC_ALGORITHM_DH => 'DH', + self::DNSSEC_ALGORITHM_DSA => 'DSA', + self::DNSSEC_ALGORITHM_ECC => 'ECC', + self::DNSSEC_ALGORITHM_RSASHA1 => 'RSASHA1', + self::DNSSEC_ALGORITHM_DSANSEC3SHA1 => 'DSA-NSEC3-SHA1', + self::DSNSEC_ALGORITHM_RSASHA1NSEC3SHA1 => 'RSASHA1-NSEC3-SHA1', + self::DNSSEC_ALGORITHM_RSASHA256 => 'RSASHA256', + self::DNSSEC_ALGORITHM_RSASHA512 => 'RSASHA512', + self::DNSSEC_ALGORITHM_ECCGOST => 'ECC-GOST', + self::DNSSEC_ALGORITHM_INDIRECT => 'INDIRECT', + self::DNSSEC_ALGORITHM_PRIVATEDNS => 'PRIVATEDNS', + self::DNSSEC_ALGORITHM_PRIVATEOID => 'PRIVATEOID' + ); + + public static $digest_name_to_id = array(); + public static $digest_id_to_name = array( + + self::DNSSEC_DIGEST_RES => 'RES', + self::DNSSEC_DIGEST_SHA1 => 'SHA-1' + ); + + public static $protocol_by_id = array(); + public static $protocol_by_name = array( + + 'ICMP' => 1, + 'IGMP' => 2, + 'GGP' => 3, + 'ST' => 5, + 'TCP' => 6, + 'UCL' => 7, + 'EGP' => 8, + 'IGP' => 9, + 'BBN-RCC-MON' => 10, + 'NVP-II' => 11, + 'PUP' => 12, + 'ARGUS' => 13, + 'EMCON' => 14, + 'XNET' => 15, + 'CHAOS' => 16, + 'UDP' => 17, + 'MUX' => 18, + 'DCN-MEAS' => 19, + 'HMP' => 20, + 'PRM' => 21, + 'XNS-IDP' => 22, + 'TRUNK-1' => 23, + 'TRUNK-2' => 24, + 'LEAF-1' => 25, + 'LEAF-2' => 26, + 'RDP' => 27, + 'IRTP' => 28, + 'ISO-TP4' => 29, + 'NETBLT' => 30, + 'MFE-NSP' => 31, + 'MERIT-INP' => 32, + 'SEP' => 33, + + 'CFTP' => 62, + + 'SAT-EXPAK' => 64, + 'MIT-SUBNET' => 65, + 'RVD' => 66, + 'IPPC' => 67, + + 'SAT-MON' => 69, + + 'IPCV' => 71, + + 'BR-SAT-MON' => 76, + + 'WB-MON' => 78, + 'WB-EXPAK' => 79 + + ); +} + +?>header->__toString(); + + foreach ($this->question as $x) { + + $output .= $x->__toString() . "\n"; + } + foreach ($this->answer as $x) { + + $output .= $x->__toString() . "\n"; + } + foreach ($this->authority as $x) { + + $output .= $x->__toString() . "\n"; + } + foreach ($this->additional as $x) { + + $output .= $x->__toString() . "\n"; + } + + return $output; + } + + public function get() + { + $data = $this->header->get($this); + + foreach ($this->question as $x) { + + $data .= $x->get($this); + } + foreach ($this->answer as $x) { + + $data .= $x->get($this); + } + foreach ($this->authority as $x) { + + $data .= $x->get($this); + } + foreach ($this->additional as $x) { + + $data .= $x->get($this); + } + + return $data; + } + + public function compress($name, &$offset) + { + $names = explode('.', $name); + $compname = ''; + + while (!empty($names)) { + + $dname = join('.', $names); + + if (isset($this->_compressed[$dname])) { + + $compname .= pack('n', 0xc000 | $this->_compressed[$dname]); + $offset += 2; + + break; + } + + $this->_compressed[$dname] = $offset; + $first = array_shift($names); + + $length = strlen($first); + if ($length <= 0) { + continue; + } + + // + + // + if ($length > 63) { + + $length = 63; + $first = substr($first, 0, $length); + } + + $compname .= pack('Ca*', $length, $first); + $offset += $length + 1; + } + + if (empty($names)) { + + $compname .= pack('C', 0); + $offset++; + } + + return $compname; + } + + public static function pack($name) + { + $offset = 0; + $names = explode('.', $name); + $compname = ''; + + while (!empty($names)) { + + $first = array_shift($names); + $length = strlen($first); + + $compname .= pack('Ca*', $length, $first); + $offset += $length + 1; + } + + $compname .= "\0"; + $offset++; + + return $compname; + } + + public static function expand(Net_DNS2_Packet &$packet, &$offset) + { + $name = ''; + + while (1) { + if ($packet->rdlength < ($offset + 1)) { + return null; + } + + $xlen = ord($packet->rdata[$offset]); + if ($xlen == 0) { + + ++$offset; + break; + + } else if (($xlen & 0xc0) == 0xc0) { + if ($packet->rdlength < ($offset + 2)) { + + return null; + } + + $ptr = ord($packet->rdata[$offset]) << 8 | + ord($packet->rdata[$offset+1]); + $ptr = $ptr & 0x3fff; + + $name2 = Net_DNS2_Packet::expand($packet, $ptr); + if (is_null($name2)) { + + return null; + } + + $name .= $name2; + $offset += 2; + + break; + } else { + ++$offset; + + if ($packet->rdlength < ($offset + $xlen)) { + + return null; + } + + $elem = ''; + $elem = substr($packet->rdata, $offset, $xlen); + $name .= $elem . '.'; + $offset += $xlen; + } + } + + return trim($name, '.'); + } + + public static function label(Net_DNS2_Packet &$packet, &$offset) + { + $name = ''; + + if ($packet->rdlength < ($offset + 1)) { + + return null; + } + + $xlen = ord($packet->rdata[$offset]); + ++$offset; + + if (($xlen + $offset) > $packet->rdlength) { + + $name = substr($packet->rdata, $offset); + $offset = $packet->rdlength; + } else { + + $name = substr($packet->rdata, $offset, $xlen); + $offset += $xlen; + } + + return $name; + } + + public function copy(Net_DNS2_Packet $packet) + { + $this->header = $packet->header; + $this->question = $packet->question; + $this->answer = $packet->answer; + $this->authority = $packet->authority; + $this->additional = $packet->additional; + + return true; + } + + public function reset() + { + $this->header->id = $this->header->nextPacketId(); + $this->rdata = ''; + $this->rdlength = 0; + $this->offset = 0; + $this->answer = array(); + $this->authority = array(); + $this->additional = array(); + $this->_compressed = array(); + + return true; + } + + public static function formatIPv6($address) + { + return Net_DNS2::expandIPv6($address); + } +} + +?>parseFile($file); + } + } + + public function parseFile($file) + { + // + + // + if (extension_loaded('openssl') === false) { + + throw new Net_DNS2_Exception( + 'the OpenSSL extension is required to use parse private key.', + Net_DNS2_Lookups::E_OPENSSL_UNAVAIL + ); + } + + // + + // + if (is_readable($file) == false) { + + throw new Net_DNS2_Exception( + 'invalid private key file: ' . $file, + Net_DNS2_Lookups::E_OPENSSL_INV_PKEY + ); + } + + // + + // + $keyname = basename($file); + if (strlen($keyname) == 0) { + + throw new Net_DNS2_Exception( + 'failed to get basename() for: ' . $file, + Net_DNS2_Lookups::E_OPENSSL_INV_PKEY + ); + } + + // + + // + if (preg_match("/K(.*)\.\+(\d{3})\+(\d*)\.private/", $keyname, $matches)) { + + $this->signname = $matches[1]; + $this->algorithm = intval($matches[2]); + $this->keytag = intval($matches[3]); + + } else { + + throw new Net_DNS2_Exception( + 'file ' . $keyname . ' does not look like a private key file!', + Net_DNS2_Lookups::E_OPENSSL_INV_PKEY + ); + } + + // + + // + $data = file($file, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if (count($data) == 0) { + + throw new Net_DNS2_Exception( + 'file ' . $keyname . ' is empty!', + Net_DNS2_Lookups::E_OPENSSL_INV_PKEY + ); + } + + foreach ($data as $line) { + + list($key, $value) = explode(':', $line); + + $key = trim($key); + $value = trim($value); + + switch(strtolower($key)) { + + case 'private-key-format': + $this->_key_format = $value; + break; + + case 'algorithm': + if ($this->algorithm != $value) { + throw new Net_DNS2_Exception( + 'Algorithm mis-match! filename is ' . $this->algorithm . + ', contents say ' . $value, + Net_DNS2_Lookups::E_OPENSSL_INV_ALGO + ); + } + break; + + // + + // + case 'modulus': + $this->_modulus = $value; + break; + + case 'publicexponent': + $this->_public_exponent = $value; + break; + + case 'privateexponent': + $this->_private_exponent = $value; + break; + + case 'prime1': + $this->_prime1 = $value; + break; + + case 'prime2': + $this->_prime2 = $value; + break; + + case 'exponent1': + $this->_exponent1 = $value; + break; + + case 'exponent2': + $this->_exponent2 = $value; + break; + + case 'coefficient': + $this->_coefficient = $value; + break; + + // + + // + case 'prime(p)': + $this->prime = $value; + break; + + case 'subprime(q)': + $this->subprime = $value; + break; + + case 'base(g)': + $this->base = $value; + break; + + case 'private_value(x)': + $this->private_value = $value; + break; + + case 'public_value(y)': + $this->public_value = $value; + break; + + default: + throw new Net_DNS2_Exception( + 'unknown private key data: ' . $key . ': ' . $value, + Net_DNS2_Lookups::E_OPENSSL_INV_PKEY + ); + } + } + + // + + // + $args = array(); + + switch($this->algorithm) { + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512: + + $args = array( + + 'rsa' => array( + + 'n' => base64_decode($this->_modulus), + 'e' => base64_decode($this->_public_exponent), + 'd' => base64_decode($this->_private_exponent), + 'p' => base64_decode($this->_prime1), + 'q' => base64_decode($this->_prime2), + 'dmp1' => base64_decode($this->_exponent1), + 'dmq1' => base64_decode($this->_exponent2), + 'iqmp' => base64_decode($this->_coefficient) + ) + ); + + break; + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSA: + + $args = array( + + 'dsa' => array( + + 'p' => base64_decode($this->prime), + 'q' => base64_decode($this->subprime), + 'g' => base64_decode($this->base), + 'priv_key' => base64_decode($this->private_value), + 'pub_key' => base64_decode($this->public_value) + ) + ); + + break; + + default: + throw new Net_DNS2_Exception( + 'we only currently support RSAMD5 and RSASHA1 encryption.', + Net_DNS2_Lookups::E_OPENSSL_INV_PKEY + ); + } + + // + + // + $this->instance = openssl_pkey_new($args); + if ($this->instance === false) { + throw new Net_DNS2_Exception( + openssl_error_string(), + Net_DNS2_Lookups::E_OPENSSL_ERROR + ); + } + + // + + // + $this->filename = $file; + + return true; + } +} + +?>set($packet); + } else { + + $this->qname = ''; + $this->qtype = 'A'; + $this->qclass = 'IN'; + } + } + + public function __toString() + { + return ";;\n;; Question:\n;;\t " . $this->qname . '. ' . + $this->qtype . ' ' . $this->qclass . "\n"; + } + + public function set(Net_DNS2_Packet &$packet) + { + // + + // + $this->qname = $packet->expand($packet, $packet->offset); + if ($packet->rdlength < ($packet->offset + 4)) { + + throw new Net_DNS2_Exception( + 'invalid question section: to small', + Net_DNS2_Lookups::E_QUESTION_INVALID + ); + } + + // + + // + $type = ord($packet->rdata[$packet->offset++]) << 8 | + ord($packet->rdata[$packet->offset++]); + $class = ord($packet->rdata[$packet->offset++]) << 8 | + ord($packet->rdata[$packet->offset++]); + + // + + // + $type_name = Net_DNS2_Lookups::$rr_types_by_id[$type]; + $class_name = Net_DNS2_Lookups::$classes_by_id[$class]; + + if ( (!isset($type_name)) || (!isset($class_name)) ) { + + throw new Net_DNS2_Exception( + 'invalid question section: invalid type (' . $type . + ') or class (' . $class . ') specified.', + Net_DNS2_Lookups::E_QUESTION_INVALID + ); + } + + // + + // + $this->qtype = $type_name; + $this->qclass = $class_name; + + return true; + } + + public function get(Net_DNS2_Packet &$packet) + { + // + + // + $type = Net_DNS2_Lookups::$rr_types_by_name[$this->qtype]; + $class = Net_DNS2_Lookups::$classes_by_name[$this->qclass]; + + if ( (!isset($type)) || (!isset($class)) ) { + + throw new Net_DNS2_Exception( + 'invalid question section: invalid type (' . $this->qtype . + ') or class (' . $this->qclass . ') specified.', + Net_DNS2_Lookups::E_QUESTION_INVALID + ); + } + + $data = $packet->compress($this->qname, $packet->offset); + + $data .= chr($type << 8) . chr($type) . chr($class << 8) . chr($class); + $packet->offset += 4; + + return $data; + } +} + +?>checkServers(Net_DNS2::RESOLV_CONF); + + // + + // + if ($type == 'IXFR') { + + $type = 'AXFR'; + } + + // + + // + if ( (strpos($name, '.') === false) && ($type != 'PTR') ) { + + $name .= '.' . strtolower($this->domain); + } + + // + + // + $packet = new Net_DNS2_Packet_Request($name, $type, $class); + + // + + // + if ( ($this->auth_signature instanceof Net_DNS2_RR_TSIG) + || ($this->auth_signature instanceof Net_DNS2_RR_SIG) + ) { + $packet->additional[] = $this->auth_signature; + $packet->header->arcount = count($packet->additional); + } + + // + + // + if ($this->dnssec == true) { + + // + + // + $opt = new Net_DNS2_RR_OPT(); + + // + + // + $opt->do = 1; + $opt->class = $this->dnssec_payload_size; + + // + + // + $packet->additional[] = $opt; + $packet->header->arcount = count($packet->additional); + } + + // + + // + if ($this->dnssec_ad_flag == true) { + + $packet->header->ad = 1; + } + if ($this->dnssec_cd_flag == true) { + + $packet->header->cd = 1; + } + + // + + // + + // + $packet_hash = ''; + + if ( ($this->use_cache == true) && ($this->cacheable($type) == true) ) { + + // + + // + $this->cache->open( + $this->cache_file, $this->cache_size, $this->cache_serializer + ); + + // + + // + $packet_hash = md5( + $packet->question[0]->qname . '|' . $packet->question[0]->qtype + ); + + if ($this->cache->has($packet_hash)) { + + return $this->cache->get($packet_hash); + } + } + + // + + // + if ($this->recurse == false) { + $packet->header->rd = 0; + } else { + $packet->header->rd = 1; + } + + // + + // + + // + $response = $this->sendPacket( + $packet, ($type == 'AXFR') ? true : $this->use_tcp + ); + + // + + // + + // + if ( ($this->strict_query_mode == true) + && ($response->header->ancount > 0) + ) { + + $found = false; + + // + + // + foreach ($response->answer as $index => $object) { + + if ( (strcasecmp($object->name, $name) == 0) + && ($object->type == $type) + && ($object->class == $class) + ) { + $found = true; + break; + } + } + + // + + // + + // + if ($found == false) { + + $response->answer = array(); + $response->header->ancount = 0; + } + } + + // + + // + if ( ($this->use_cache == true) && ($this->cacheable($type) == true) ) { + + $this->cache->put($packet_hash, $response); + } + + return $response; + } + + public function iquery(Net_DNS2_RR $rr) + { + // + + // + $this->checkServers(Net_DNS2::RESOLV_CONF); + + // + + // + $packet = new Net_DNS2_Packet_Request($rr->name, 'A', 'IN'); + + // + + // + $packet->question = array(); + $packet->header->qdcount = 0; + + // + + // + $packet->header->opcode = Net_DNS2_Lookups::OPCODE_IQUERY; + + // + + // + $packet->answer[] = $rr; + $packet->header->ancount = 1; + + // + + // + if ( ($this->auth_signature instanceof Net_DNS2_RR_TSIG) + || ($this->auth_signature instanceof Net_DNS2_RR_SIG) + ) { + $packet->additional[] = $this->auth_signature; + $packet->header->arcount = count($packet->additional); + } + + // + + // + return $this->sendPacket($packet, $this->use_tcp); + } +} + +?>set($packet, $rr) == false) { + + throw new Net_DNS2_Exception( + 'failed to generate resource record', + Net_DNS2_Lookups::E_RR_INVALID + ); + } + } else { + + $class = Net_DNS2_Lookups::$rr_types_class_to_id[get_class($this)]; + if (isset($class)) { + + $this->type = Net_DNS2_Lookups::$rr_types_by_id[$class]; + } + + $this->class = 'IN'; + $this->ttl = 86400; + } + } + + public function __toString() + { + return $this->name . '. ' . $this->ttl . ' ' . $this->class . + ' ' . $this->type . ' ' . $this->rrToString(); + } + + protected function formatString($string) + { + return '"' . str_replace('"', '\"', trim($string, '"')) . '"'; + } + + protected function buildString(array $chunks) + { + $data = array(); + $c = 0; + $in = false; + + foreach ($chunks as $r) { + + $r = trim($r); + if (strlen($r) == 0) { + continue; + } + + if ( ($r[0] == '"') + && ($r[strlen($r) - 1] == '"') + && ($r[strlen($r) - 2] != '\\') + ) { + + $data[$c] = $r; + ++$c; + $in = false; + + } else if ($r[0] == '"') { + + $data[$c] = $r; + $in = true; + + } else if ( ($r[strlen($r) - 1] == '"') + && ($r[strlen($r) - 2] != '\\') + ) { + + $data[$c] .= ' ' . $r; + ++$c; + $in = false; + + } else { + + if ($in == true) { + $data[$c] .= ' ' . $r; + } else { + $data[$c++] = $r; + } + } + } + + foreach ($data as $index => $string) { + + $data[$index] = str_replace('\"', '"', trim($string, '"')); + } + + return $data; + } + + public function set(Net_DNS2_Packet &$packet, array $rr) + { + $this->name = $rr['name']; + $this->type = Net_DNS2_Lookups::$rr_types_by_id[$rr['type']]; + + // + + // + if ($this->type == 'OPT') { + $this->class = $rr['class']; + } else { + $this->class = Net_DNS2_Lookups::$classes_by_id[$rr['class']]; + } + + $this->ttl = $rr['ttl']; + $this->rdlength = $rr['rdlength']; + $this->rdata = substr($packet->rdata, $packet->offset, $rr['rdlength']); + + return $this->rrSet($packet); + } + + public function get(Net_DNS2_Packet &$packet) + { + $data = ''; + $rdata = ''; + + // + + // + $data = $packet->compress($this->name, $packet->offset); + + // + + // + if ($this->type == 'OPT') { + + // + + // + $this->preBuild(); + + // + + // + $data .= pack( + 'nnN', + Net_DNS2_Lookups::$rr_types_by_name[$this->type], + $this->class, + $this->ttl + ); + } else { + + $data .= pack( + 'nnN', + Net_DNS2_Lookups::$rr_types_by_name[$this->type], + Net_DNS2_Lookups::$classes_by_name[$this->class], + $this->ttl + ); + } + + // + + // + $packet->offset += 10; + + // + + // + if ($this->rdlength != -1) { + + $rdata = $this->rrGet($packet); + } + + // + + // + $data .= pack('n', strlen($rdata)) . $rdata; + + return $data; + } + + public static function parse(Net_DNS2_Packet &$packet) + { + $object = array(); + + // + + // + $object['name'] = $packet->expand($packet, $packet->offset); + if (is_null($object['name'])) { + + throw new Net_DNS2_Exception( + 'failed to parse resource record: failed to expand name.', + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + if ($packet->rdlength < ($packet->offset + 10)) { + + throw new Net_DNS2_Exception( + 'failed to parse resource record: packet too small.', + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + + // + + // + $object['type'] = ord($packet->rdata[$packet->offset++]) << 8 | + ord($packet->rdata[$packet->offset++]); + $object['class'] = ord($packet->rdata[$packet->offset++]) << 8 | + ord($packet->rdata[$packet->offset++]); + + $object['ttl'] = ord($packet->rdata[$packet->offset++]) << 24 | + ord($packet->rdata[$packet->offset++]) << 16 | + ord($packet->rdata[$packet->offset++]) << 8 | + ord($packet->rdata[$packet->offset++]); + + $object['rdlength'] = ord($packet->rdata[$packet->offset++]) << 8 | + ord($packet->rdata[$packet->offset++]); + + if ($packet->rdlength < ($packet->offset + $object['rdlength'])) { + return null; + } + + // + + // + $o = null; + $class = Net_DNS2_Lookups::$rr_types_id_to_class[$object['type']]; + + if (isset($class)) { + + $o = new $class($packet, $object); + if ($o) { + + $packet->offset += $object['rdlength']; + } + } else { + + throw new Net_DNS2_Exception( + 'un-implemented resource record type: ' . $object['type'], + Net_DNS2_Lookups::E_RR_INVALID + ); + } + + return $o; + } + + public function cleanString($data) + { + return strtolower(rtrim($data, '.')); + } + + public static function fromString($line) + { + if (strlen($line) == 0) { + throw new Net_DNS2_Exception( + 'empty config line provided.', + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + + $name = ''; + $type = ''; + $class = 'IN'; + $ttl = 86400; + + // + + // + $values = preg_split('/[\s]+/', $line); + if (count($values) < 3) { + + throw new Net_DNS2_Exception( + 'failed to parse config: minimum of name, type and rdata required.', + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + + // + + // + $name = trim(strtolower(array_shift($values)), '.'); + + // + + // + foreach ($values as $value) { + + switch($value) { + case is_numeric($value): + + $ttl = array_shift($values); + break; + + // + + // + case ($value === 0): + $ttl = array_shift($values); + break; + + case isset(Net_DNS2_Lookups::$classes_by_name[strtoupper($value)]): + + $class = strtoupper(array_shift($values)); + break; + + case isset(Net_DNS2_Lookups::$rr_types_by_name[strtoupper($value)]): + + $type = strtoupper(array_shift($values)); + break 2; + break; + default: + + throw new Net_DNS2_Exception( + 'invalid config line provided: unknown file: ' . $value, + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + } + + // + + // + $o = null; + $class_name = Net_DNS2_Lookups::$rr_types_id_to_class[ + Net_DNS2_Lookups::$rr_types_by_name[$type] + ]; + + if (isset($class_name)) { + + $o = new $class_name; + if (!is_null($o)) { + + // + + // + $o->name = $name; + $o->class = $class; + $o->ttl = $ttl; + + // + + // + if ($o->rrFromString($values) === false) { + + throw new Net_DNS2_Exception( + 'failed to parse rdata for config: ' . $line, + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + + } else { + + throw new Net_DNS2_Exception( + 'failed to create new RR record for type: ' . $type, + Net_DNS2_Lookups::E_RR_INVALID + ); + } + + } else { + + throw new Net_DNS2_Exception( + 'un-implemented resource record type: '. $type, + Net_DNS2_Lookups::E_RR_INVALID + ); + } + + return $o; + } +} + +?>type = $type; + $this->host = $host; + $this->port = $port; + $this->timeout = $timeout; + } + + public function __destruct() + { + $this->close(); + } + + public function bindAddress($address, $port = 0) + { + $this->local_host = $address; + $this->local_port = $port; + + return true; + } + + abstract public function open(); + + abstract public function close(); + + abstract public function write($data); + + abstract public function read(&$size, $max_size); +} + +?>_packet = new Net_DNS2_Packet_Request( + strtolower(trim($zone, " \n\r\t.")), 'SOA', 'IN' + ); + + // + + // + $this->_packet->header->opcode = Net_DNS2_Lookups::OPCODE_UPDATE; + } + + private function _checkName($name) + { + if (!preg_match('/' . $this->_packet->question[0]->qname . '$/', $name)) { + + throw new Net_DNS2_Exception( + 'name provided (' . $name . ') does not match zone name (' . + $this->_packet->question[0]->qname . ')', + Net_DNS2_Lookups::E_PACKET_INVALID + ); + } + + return true; + } + + public function signature($keyname, $signature) + { + return $this->signTSIG($keyname, $signature); + } + + public function add(Net_DNS2_RR $rr) + { + $this->_checkName($rr->name); + + // + + // + if (!in_array($rr, $this->_packet->authority)) { + $this->_packet->authority[] = $rr; + } + + return true; + } + + public function delete(Net_DNS2_RR $rr) + { + $this->_checkName($rr->name); + + $rr->ttl = 0; + $rr->class = 'NONE'; + + // + + // + if (!in_array($rr, $this->_packet->authority)) { + $this->_packet->authority[] = $rr; + } + + return true; + } + + public function deleteAny($name, $type) + { + $this->_checkName($name); + + $class = Net_DNS2_Lookups::$rr_types_id_to_class[ + Net_DNS2_Lookups::$rr_types_by_name[$type] + ]; + if (!isset($class)) { + + throw new Net_DNS2_Exception( + 'unknown or un-supported resource record type: ' . $type, + Net_DNS2_Lookups::E_RR_INVALID + ); + } + + $rr = new $class; + + $rr->name = $name; + $rr->ttl = 0; + $rr->class = 'ANY'; + $rr->rdlength = -1; + $rr->rdata = ''; + + // + + // + if (!in_array($rr, $this->_packet->authority)) { + $this->_packet->authority[] = $rr; + } + + return true; + } + + public function deleteAll($name) + { + $this->_checkName($name); + + // + + // + $rr = new Net_DNS2_RR_ANY; + + $rr->name = $name; + $rr->ttl = 0; + $rr->type = 'ANY'; + $rr->class = 'ANY'; + $rr->rdlength = -1; + $rr->rdata = ''; + + // + + // + if (!in_array($rr, $this->_packet->authority)) { + $this->_packet->authority[] = $rr; + } + + return true; + } + + public function checkExists($name, $type) + { + $this->_checkName($name); + + $class = Net_DNS2_Lookups::$rr_types_id_to_class[ + Net_DNS2_Lookups::$rr_types_by_name[$type] + ]; + if (!isset($class)) { + + throw new Net_DNS2_Exception( + 'unknown or un-supported resource record type: ' . $type, + Net_DNS2_Lookups::E_RR_INVALID + ); + } + + $rr = new $class; + + $rr->name = $name; + $rr->ttl = 0; + $rr->class = 'ANY'; + $rr->rdlength = -1; + $rr->rdata = ''; + + // + + // + if (!in_array($rr, $this->_packet->answer)) { + $this->_packet->answer[] = $rr; + } + + return true; + } + + public function checkValueExists(Net_DNS2_RR $rr) + { + $this->_checkName($rr->name); + + $rr->ttl = 0; + + // + + // + if (!in_array($rr, $this->_packet->answer)) { + $this->_packet->answer[] = $rr; + } + + return true; + } + + public function checkNotExists($name, $type) + { + $this->_checkName($name); + + $class = Net_DNS2_Lookups::$rr_types_id_to_class[ + Net_DNS2_Lookups::$rr_types_by_name[$type] + ]; + if (!isset($class)) { + + throw new Net_DNS2_Exception( + 'unknown or un-supported resource record type: ' . $type, + Net_DNS2_Lookups::E_RR_INVALID + ); + } + + $rr = new $class; + + $rr->name = $name; + $rr->ttl = 0; + $rr->class = 'NONE'; + $rr->rdlength = -1; + $rr->rdata = ''; + + // + + // + if (!in_array($rr, $this->_packet->answer)) { + $this->_packet->answer[] = $rr; + } + + return true; + } + + public function checkNameInUse($name) + { + $this->_checkName($name); + + // + + // + $rr = new Net_DNS2_RR_ANY; + + $rr->name = $name; + $rr->ttl = 0; + $rr->type = 'ANY'; + $rr->class = 'ANY'; + $rr->rdlength = -1; + $rr->rdata = ''; + + // + + // + if (!in_array($rr, $this->_packet->answer)) { + $this->_packet->answer[] = $rr; + } + + return true; + } + + public function checkNameNotInUse($name) + { + $this->_checkName($name); + + // + + // + $rr = new Net_DNS2_RR_ANY; + + $rr->name = $name; + $rr->ttl = 0; + $rr->type = 'ANY'; + $rr->class = 'NONE'; + $rr->rdlength = -1; + $rr->rdata = ''; + + // + + // + if (!in_array($rr, $this->_packet->answer)) { + $this->_packet->answer[] = $rr; + } + + return true; + } + + public function packet() + { + // + + // + $p = $this->_packet; + + // + + // + if ( ($this->auth_signature instanceof Net_DNS2_RR_TSIG) + || ($this->auth_signature instanceof Net_DNS2_RR_SIG) + ) { + $p->additional[] = $this->auth_signature; + } + + // + + // + $p->header->qdcount = count($p->question); + $p->header->ancount = count($p->answer); + $p->header->nscount = count($p->authority); + $p->header->arcount = count($p->additional); + + return $p; + } + + public function update(&$response = null) + { + // + + // + $this->checkServers(Net_DNS2::RESOLV_CONF); + + // + + // + if ( ($this->auth_signature instanceof Net_DNS2_RR_TSIG) + || ($this->auth_signature instanceof Net_DNS2_RR_SIG) + ) { + $this->_packet->additional[] = $this->auth_signature; + } + + // + + // + $this->_packet->header->qdcount = count($this->_packet->question); + $this->_packet->header->ancount = count($this->_packet->answer); + $this->_packet->header->nscount = count($this->_packet->authority); + $this->_packet->header->arcount = count($this->_packet->additional); + + // + + // + if ( ($this->_packet->header->qdcount == 0) + || ($this->_packet->header->nscount == 0) + ) { + throw new Net_DNS2_Exception( + 'empty headers- nothing to send!', + Net_DNS2_Lookups::E_PACKET_INVALID + ); + } + + // + + // + $response = $this->sendPacket($this->_packet, $this->use_tcp); + + // + + // + $this->_packet->reset(); + + // + + // + return true; + } +} + +?>cache_size = $size; + $this->cache_file = $cache_file; + $this->cache_serializer = $serializer; + + // + + // + if ( (file_exists($this->cache_file) == true) + && (filesize($this->cache_file) > 0) + ) { + + // + + // + $fp = @fopen($this->cache_file, 'r'); + if ($fp !== false) { + + // + + // + flock($fp, LOCK_EX); + + // + + // + $data = fread($fp, filesize($this->cache_file)); + + $decoded = null; + + if ($this->cache_serializer == 'json') { + + $decoded = json_decode($data, true); + } else { + + $decoded = unserialize($data); + } + + if (is_array($decoded) == true) { + + $this->cache_data = $decoded; + } else { + + $this->cache_data = array(); + } + + // + + // + flock($fp, LOCK_UN); + + // + + // + fclose($fp); + + // + + // + $this->clean(); + } + } + } + + public function __destruct() + { + // + + // + if (strlen($this->cache_file) == 0) { + return; + } + + // + + // + $fp = fopen($this->cache_file, 'a+'); + if ($fp !== false) { + + // + + // + flock($fp, LOCK_EX); + + // + + // + fseek($fp, 0, SEEK_SET); + + // + + // + $data = @fread($fp, filesize($this->cache_file)); + if ( ($data !== false) && (strlen($data) > 0) ) { + + // + + // + $c = $this->cache_data; + + $decoded = null; + + if ($this->cache_serializer == 'json') { + + $decoded = json_decode($data, true); + } else { + + $decoded = unserialize($data); + } + + if (is_array($decoded) == true) { + + $this->cache_data = array_merge($c, $decoded); + } + } + + // + + // + ftruncate($fp, 0); + + // + + // + $this->clean(); + + // + + // + $data = $this->resize(); + if (!is_null($data)) { + + // + + // + fwrite($fp, $data); + } + + // + + // + flock($fp, LOCK_UN); + + // + + // + fclose($fp); + } + } +}; + +?>cache_size = $size; + $this->cache_file = $cache_file; + $this->cache_serializer = $serializer; + + // + + // + if (!file_exists($cache_file)) { + + if (file_put_contents($cache_file, '') === false) { + + throw new Net_DNS2_Exception( + 'failed to create empty SHM file: ' . $cache_file, + Net_DNS2_Lookups::E_CACHE_SHM_FILE + ); + } + } + + // + + // + $this->_cache_file_tok = ftok($cache_file, 't'); + if ($this->_cache_file_tok == -1) { + + throw new Net_DNS2_Exception( + 'failed on ftok() file: ' . $this->_cache_file_tok, + Net_DNS2_Lookups::E_CACHE_SHM_FILE + ); + } + + // + + // + $this->_cache_id = @shmop_open($this->_cache_file_tok, 'w', 0, 0); + if ($this->_cache_id !== false) { + + // + + // + $allocated = shmop_size($this->_cache_id); + if ($allocated > 0) { + + // + + // + $data = trim(shmop_read($this->_cache_id, 0, $allocated)); + if ( ($data !== false) && (strlen($data) > 0) ) { + + // + + // + $decoded = null; + + if ($this->cache_serializer == 'json') { + + $decoded = json_decode($data, true); + } else { + + $decoded = unserialize($data); + } + + if (is_array($decoded) == true) { + + $this->cache_data = $decoded; + } else { + + $this->cache_data = array(); + } + + // + + // + $this->clean(); + } + } + } + } + + public function __destruct() + { + // + + // + if (strlen($this->cache_file) == 0) { + return; + } + + $fp = fopen($this->cache_file, 'r'); + if ($fp !== false) { + + // + + // + flock($fp, LOCK_EX); + + // + + // + if ($this->_cache_id === false) { + + // + + // + $this->_cache_id = @shmop_open( + $this->_cache_file_tok, 'w', 0, 0 + ); + if ($this->_cache_id === false) { + + // + + // + $this->_cache_id = @shmop_open( + $this->_cache_file_tok, 'c', 0, $this->cache_size + ); + } + } + + // + + // + $allocated = shmop_size($this->_cache_id); + + // + + // + $data = trim(shmop_read($this->_cache_id, 0, $allocated)); + + // + + // + if ( ($data !== false) && (strlen($data) > 0) ) { + + // + + // + $c = $this->cache_data; + + $decoded = null; + + if ($this->cache_serializer == 'json') { + + $decoded = json_decode($data, true); + } else { + + $decoded = unserialize($data); + } + + if (is_array($decoded) == true) { + + $this->cache_data = array_merge($c, $decoded); + } + } + + // + + // + shmop_delete($this->_cache_id); + + // + + // + $this->clean(); + + // + + // + $data = $this->resize(); + if (!is_null($data)) { + + // + + // + $this->_cache_id = @shmop_open( + $this->_cache_file_tok, 'c', 0644, $this->cache_size + ); + if ($this->_cache_id === false) { + return; + } + + $o = shmop_write($this->_cache_id, $data, 0); + } + + // + + // + shmop_close($this->_cache_id); + + // + + // + flock($fp, LOCK_UN); + + // + + // + fclose($fp); + } + } +}; + +?>set($name, $type, $class); + } + + public function set($name, $type = 'A', $class = 'IN') + { + // + + // + $this->header = new Net_DNS2_Header; + + // + + // + $q = new Net_DNS2_Question(); + + // + + // + if ($name != '.') { + $name = trim(strtolower($name), " \t\n\r\0\x0B."); + } + + $type = strtoupper(trim($type)); + $class = strtoupper(trim($class)); + + // + + // + if (empty($name)) { + + throw new Net_DNS2_Exception( + 'empty query string provided', + Net_DNS2_Lookups::E_PACKET_INVALID + ); + } + + // + + // + if ($type == '*') { + + $type = 'ANY'; + } + + // + + // + if ( (!isset(Net_DNS2_Lookups::$rr_types_by_name[$type])) + || (!isset(Net_DNS2_Lookups::$classes_by_name[$class])) + ) { + throw new Net_DNS2_Exception( + 'invalid type (' . $type . ') or class (' . $class . ') specified.', + Net_DNS2_Lookups::E_PACKET_INVALID + ); + } + + if ($type == 'PTR') { + + // + + // + + // + if (Net_DNS2::isIPv4($name) == true) { + + // + + // + $name = implode('.', array_reverse(explode('.', $name))); + $name .= '.in-addr.arpa'; + + } else if (Net_DNS2::isIPv6($name) == true) { + + // + + // + $e = Net_DNS2::expandIPv6($name); + if ($e !== false) { + + $name = implode( + '.', array_reverse(str_split(str_replace(':', '', $e))) + ); + + $name .= '.ip6.arpa'; + + } else { + + throw new Net_DNS2_Exception( + 'unsupported PTR value: ' . $name, + Net_DNS2_Lookups::E_PACKET_INVALID + ); + } + } + } + + // + + // + $q->qname = $name; + $q->qtype = $type; + $q->qclass = $class; + + $this->question[] = $q; + + // + + // + $this->answer = array(); + $this->authority = array(); + $this->additional = array(); + + return true; + } +} + +?>set($data, $size); + } + + public function set($data, $size) + { + // + + // + $this->rdata = $data; + $this->rdlength = $size; + + // + + // + + // + $this->header = new Net_DNS2_Header($this); + + // + + // + + // + if ($this->header->tc == 1) { + + return false; + } + + // + + // + for ($x = 0; $x < $this->header->qdcount; ++$x) { + + $this->question[$x] = new Net_DNS2_Question($this); + } + + // + + // + for ($x = 0; $x < $this->header->ancount; ++$x) { + + $o = Net_DNS2_RR::parse($this); + if (!is_null($o)) { + + $this->answer[] = $o; + } + } + + // + + // + for ($x = 0; $x < $this->header->nscount; ++$x) { + + $o = Net_DNS2_RR::parse($this); + if (!is_null($o)) { + + $this->authority[] = $o; + } + } + + // + + // + for ($x = 0; $x < $this->header->arcount; ++$x) { + + $o = Net_DNS2_RR::parse($this); + if (!is_null($o)) { + + $this->additional[] = $o; + } + } + + return true; + } +} + +?>address; + } + + protected function rrFromString(array $rdata) + { + $value = array_shift($rdata); + + if (Net_DNS2::isIPv4($value) == true) { + + $this->address = $value; + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $this->address = inet_ntop($this->rdata); + if ($this->address !== false) { + + return true; + } + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $packet->offset += 4; + return inet_pton($this->address); + } +} + +?>address; + } + + protected function rrFromString(array $rdata) + { + // + + // + $value = array_shift($rdata); + if (Net_DNS2::isIPv6($value) == true) { + + $this->address = $value; + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + // + + // + if ($this->rdlength == 16) { + + // + + // + $x = unpack('n8', $this->rdata); + if (count($x) == 8) { + + $this->address = vsprintf('%x:%x:%x:%x:%x:%x:%x:%x', $x); + return true; + } + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $packet->offset += 16; + return inet_pton($this->address); + } +} + +?>subtype . ' ' . $this->cleanString($this->hostname) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->subtype = array_shift($rdata); + $this->hostname = $this->cleanString(array_shift($rdata)); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('nsubtype', $this->rdata); + + $this->subtype = $x['subtype']; + $offset = $packet->offset + 2; + + $this->hostname = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->hostname) > 0) { + + $data = pack('n', $this->subtype); + $packet->offset += 2; + + $data .= $packet->compress($this->hostname, $packet->offset); + + return $data; + } + + return null; + } +} + +?>apl_items as $item) { + + if ($item['n'] == 1) { + + $out .= '!'; + } + + $out .= $item['address_family'] . ':' . + $item['afd_part'] . '/' . $item['prefix'] . ' '; + } + + return trim($out); + } + + protected function rrFromString(array $rdata) + { + foreach ($rdata as $item) { + + if (preg_match('/^(!?)([1|2])\:([^\/]*)\/([0-9]{1,3})$/', $item, $m)) { + + $i = array( + + 'address_family' => $m[2], + 'prefix' => $m[4], + 'n' => ($m[1] == '!') ? 1 : 0, + 'afd_part' => strtolower($m[3]) + ); + + $address = $this->_trimZeros( + $i['address_family'], $i['afd_part'] + ); + + $i['afd_length'] = count(explode('.', $address)); + + $this->apl_items[] = $i; + } + } + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = 0; + + while ($offset < $this->rdlength) { + + // + + // + $x = unpack( + 'naddress_family/Cprefix/Cextra', substr($this->rdata, $offset) + ); + + $item = array( + + 'address_family' => $x['address_family'], + 'prefix' => $x['prefix'], + 'n' => ($x['extra'] >> 7) & 0x1, + 'afd_length' => $x['extra'] & 0xf + ); + + switch($item['address_family']) { + + case 1: + $r = unpack( + 'C*', substr($this->rdata, $offset + 4, $item['afd_length']) + ); + if (count($r) < 4) { + + for ($c=count($r)+1; $c<4+1; $c++) { + + $r[$c] = 0; + } + } + + $item['afd_part'] = implode('.', $r); + + break; + case 2: + $r = unpack( + 'C*', substr($this->rdata, $offset + 4, $item['afd_length']) + ); + if (count($r) < 8) { + + for ($c=count($r)+1; $c<8+1; $c++) { + + $r[$c] = 0; + } + } + + $item['afd_part'] = sprintf( + '%x:%x:%x:%x:%x:%x:%x:%x', + $r[1], $r[2], $r[3], $r[4], $r[5], $r[6], $r[7], $r[8] + ); + + break; + default: + return false; + } + + $this->apl_items[] = $item; + + $offset += 4 + $item['afd_length']; + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (count($this->apl_items) > 0) { + + $data = ''; + + foreach ($this->apl_items as $item) { + + // + + // + $data .= pack( + 'nCC', + $item['address_family'], + $item['prefix'], + ($item['n'] << 7) | $item['afd_length'] + ); + + switch($item['address_family']) { + case 1: + $address = explode( + '.', + $this->_trimZeros($item['address_family'], $item['afd_part']) + ); + + foreach ($address as $b) { + $data .= chr($b); + } + break; + case 2: + $address = explode( + ':', + $this->_trimZeros($item['address_family'], $item['afd_part']) + ); + + foreach ($address as $b) { + $data .= pack('H', $b); + } + break; + default: + return null; + } + } + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } + + private function _trimZeros($family, $address) + { + $a = array(); + + switch($family) { + case 1: + $a = array_reverse(explode('.', $address)); + break; + case 2: + $a = array_reverse(explode(':', $address)); + break; + default: + return ''; + } + + foreach ($a as $value) { + + if ($value === '0') { + + array_shift($a); + } + } + + $out = ''; + + switch($family) { + case 1: + $out = implode('.', array_reverse($a)); + break; + case 2: + $out = implode(':', array_reverse($a)); + break; + default: + return ''; + } + + return $out; + } +} + +?>address; + } + + protected function rrFromString(array $rdata) + { + $value = array_shift($rdata); + + if (ctype_xdigit($value) == true) { + + $this->format = 0; + $this->address = $value; + + } else if (is_numeric($value) == true) { + + $this->format = 1; + $this->address = $value; + + } else { + + return false; + } + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Cformat/N*address', $this->rdata); + + $this->format = $x['format']; + + if ($this->format == 0) { + + $a = unpack('@1/H*address', $this->rdata); + + $this->address = $a['address']; + + } else if ($this->format == 1) { + + $this->address = substr($this->rdata, 1, $this->rdlength - 1); + + } else { + + return false; + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $data = chr($this->format); + + if ($this->format == 0) { + + $data .= pack('H*', $this->address); + + } else if ($this->format == 1) { + + $data .= $this->address; + + } else { + + return null; + } + + $packet->offset += strlen($data); + + return $data; + } +} + +?>flags . ' ' . $this->tag . ' "' . + trim($this->cleanString($this->value), '"') . '"'; + } + + protected function rrFromString(array $rdata) + { + $this->flags = array_shift($rdata); + $this->tag = array_shift($rdata); + + $this->value = trim($this->cleanString(implode($rdata, ' ')), '"'); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Cflags/Ctag_length', $this->rdata); + + $this->flags = $x['flags']; + $offset = 2; + + $this->tag = substr($this->rdata, $offset, $x['tag_length']); + $offset += $x['tag_length']; + + $this->value = substr($this->rdata, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->value) > 0) { + + $data = chr($this->flags); + $data .= chr(strlen($this->tag)) . $this->tag . $this->value; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?> 'Reserved', + self::CERT_FORMAT_PKIX => 'PKIX', + self::CERT_FORMAT_SPKI => 'SPKI', + self::CERT_FORMAT_PGP => 'PGP', + self::CERT_FORMAT_IPKIX => 'IPKIX', + self::CERT_FORMAT_ISPKI => 'ISPKI', + self::CERT_FORMAT_IPGP => 'IPGP', + self::CERT_FORMAT_ACPKIX => 'ACPKIX', + self::CERT_FORMAT_IACPKIX => 'IACPKIX', + self::CERT_FORMAT_URI => 'URI', + self::CERT_FORMAT_OID => 'OID' + ); + + public $format; + + public $keytag; + + public $algorithm; + + public $certificate; + + public function __construct(Net_DNS2_Packet &$packet = null, array $rr = null) + { + parent::__construct($packet, $rr); + + // + + // + $this->cert_format_name_to_id = array_flip($this->cert_format_id_to_name); + } + + protected function rrToString() + { + return $this->format . ' ' . $this->keytag . ' ' . $this->algorithm . + ' ' . base64_encode($this->certificate); + } + + protected function rrFromString(array $rdata) + { + // + + // + $this->format = array_shift($rdata); + if (!is_numeric($this->format)) { + + $mnemonic = strtoupper(trim($this->format)); + if (!isset($this->cert_format_name_to_id[$mnemonic])) { + + return false; + } + + $this->format = $this->cert_format_name_to_id[$mnemonic]; + } else { + + if (!isset($this->cert_format_id_to_name[$this->format])) { + + return false; + } + } + + $this->keytag = array_shift($rdata); + + // + + // + $this->algorithm = array_shift($rdata); + if (!is_numeric($this->algorithm)) { + + $mnemonic = strtoupper(trim($this->algorithm)); + if (!isset(Net_DNS2_Lookups::$algorithm_name_to_id[$mnemonic])) { + + return false; + } + + $this->algorithm = Net_DNS2_Lookups::$algorithm_name_to_id[ + $mnemonic + ]; + } else { + + if (!isset(Net_DNS2_Lookups::$algorithm_id_to_name[$this->algorithm])) { + return false; + } + } + + // + + // + + // + $this->certificate = base64_decode(implode(' ', $rdata)); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('nformat/nkeytag/Calgorithm', $this->rdata); + + $this->format = $x['format']; + $this->keytag = $x['keytag']; + $this->algorithm = $x['algorithm']; + + // + + // + $this->certificate = substr($this->rdata, 5, $this->rdlength - 5); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->certificate) > 0) { + + $data = pack('nnC', $this->format, $this->keytag, $this->algorithm) . + $this->certificate; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>cleanString($this->cname) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->cname = $this->cleanString(array_shift($rdata)); + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + $this->cname = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->cname) > 0) { + + return $packet->compress($this->cname, $packet->offset); + } + + return null; + } +} + +?>serial . ' ' . $this->flags; + + // + + // + foreach ($this->type_bit_maps as $rr) { + + $out .= ' ' . strtoupper($rr); + } + + return $out; + } + + protected function rrFromString(array $rdata) + { + $this->serial = array_shift($rdata); + $this->flags = array_shift($rdata); + + $this->type_bit_maps = $rdata; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('@' . $packet->offset . '/Nserial/nflags', $packet->rdata); + + $this->serial = Net_DNS2::expandUint32($x['serial']); + $this->flags = $x['flags']; + + // + + // + $this->type_bit_maps = Net_DNS2_BitMap::bitMapToArray( + substr($this->rdata, 6) + ); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + // + + // + $data = pack('Nn', $this->serial, $this->flags); + + // + + // + $data .= Net_DNS2_BitMap::arrayToBitMap($this->type_bit_maps); + + // + + // + $packet->offset += strlen($data); + + return $data; + } +} + +?>id_type, $this->digest_type); + $out .= base64_decode($this->digest); + + return base64_encode($out); + } + + protected function rrFromString(array $rdata) + { + $data = base64_decode(array_shift($rdata)); + if (strlen($data) > 0) { + + // + + // + $x = unpack('nid_type/Cdigest_type', $data); + + $this->id_type = $x['id_type']; + $this->digest_type = $x['digest_type']; + + // + + // + $this->digest = base64_encode(substr($data, 3, strlen($data) - 3)); + + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('nid_type/Cdigest_type', $this->rdata); + + $this->id_type = $x['id_type']; + $this->digest_type = $x['digest_type']; + + // + + // + $this->digest = base64_encode( + substr($this->rdata, 3, $this->rdlength - 3) + ); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->digest) > 0) { + + $data = pack('nC', $this->id_type, $this->digest_type) . + base64_decode($this->digest); + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>cleanString($this->dname) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->dname = $this->cleanString(array_shift($rdata)); + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + $this->dname = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->dname) > 0) { + + return $packet->compress($this->dname, $packet->offset); + } + + return null; + } +} + +?>flags . ' ' . $this->protocol . ' ' . + $this->algorithm . ' ' . $this->key; + } + + protected function rrFromString(array $rdata) + { + $this->flags = array_shift($rdata); + $this->protocol = array_shift($rdata); + $this->algorithm = array_shift($rdata); + $this->key = implode(' ', $rdata); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('nflags/Cprotocol/Calgorithm', $this->rdata); + + // + + // + + // + $this->flags = $x['flags']; + $this->protocol = $x['protocol']; + $this->algorithm = $x['algorithm']; + + $this->key = base64_encode(substr($this->rdata, 4)); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->key) > 0) { + + $data = pack('nCC', $this->flags, $this->protocol, $this->algorithm); + $data .= base64_decode($this->key); + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>keytag . ' ' . $this->algorithm . ' ' . + $this->digesttype . ' ' . $this->digest; + } + + protected function rrFromString(array $rdata) + { + $this->keytag = array_shift($rdata); + $this->algorithm = array_shift($rdata); + $this->digesttype = array_shift($rdata); + $this->digest = implode('', $rdata); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('nkeytag/Calgorithm/Cdigesttype', $this->rdata); + + $this->keytag = $x['keytag']; + $this->algorithm = $x['algorithm']; + $this->digesttype = $x['digesttype']; + + // + + // + $digest_size = 0; + if ($this->digesttype == 1) { + + $digest_size = 20; + + } else if ($this->digesttype == 2) { + + $digest_size = 32; + } + + // + + // + $x = unpack('H*', substr($this->rdata, 4, $digest_size)); + $this->digest = $x[1]; + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->digest) > 0) { + + $data = pack( + 'nCCH*', + $this->keytag, $this->algorithm, $this->digesttype, $this->digest + ); + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>rdata; + } +} + +?>address; + } + + protected function rrFromString(array $rdata) + { + $value = array_shift($rdata); + + // + + // + $a = explode('-', $value); + if (count($a) != 6) { + + return false; + } + + // + + // + foreach ($a as $i) { + if (ctype_xdigit($i) == false) { + return false; + } + } + + // + + // + $this->address = strtolower($value); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $x = unpack('C6', $this->rdata); + if (count($x) == 6) { + + $this->address = vsprintf('%02x-%02x-%02x-%02x-%02x-%02x', $x); + return true; + } + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $data = ''; + + $a = explode('-', $this->address); + foreach ($a as $b) { + + $data .= chr(hexdec($b)); + } + + $packet->offset += 6; + return $data; + } +} + +?>address; + } + + protected function rrFromString(array $rdata) + { + $value = array_shift($rdata); + + // + + // + $a = explode('-', $value); + if (count($a) != 8) { + + return false; + } + + // + + // + foreach ($a as $i) { + if (ctype_xdigit($i) == false) { + return false; + } + } + + // + + // + $this->address = strtolower($value); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $x = unpack('C8', $this->rdata); + if (count($x) == 8) { + + $this->address = vsprintf( + '%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x', $x + ); + return true; + } + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $data = ''; + + $a = explode('-', $this->address); + foreach ($a as $b) { + + $data .= chr(hexdec($b)); + } + + $packet->offset += 8; + return $data; + } +} + +?>formatString($this->cpu) . ' ' . + $this->formatString($this->os); + } + + protected function rrFromString(array $rdata) + { + $data = $this->buildString($rdata); + if (count($data) == 2) { + + $this->cpu = $data[0]; + $this->os = $data[1]; + + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + + $this->cpu = trim(Net_DNS2_Packet::label($packet, $offset), '"'); + $this->os = trim(Net_DNS2_Packet::label($packet, $offset), '"'); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->cpu) > 0) { + + $data = chr(strlen($this->cpu)) . $this->cpu; + $data .= chr(strlen($this->os)) . $this->os; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>pk_algorithm . ' ' . + $this->hit . ' ' . $this->public_key . ' '; + + foreach ($this->rendezvous_servers as $index => $server) { + + $out .= $server . '. '; + } + + return trim($out); + } + + protected function rrFromString(array $rdata) + { + $this->pk_algorithm = array_shift($rdata); + $this->hit = strtoupper(array_shift($rdata)); + $this->public_key = array_shift($rdata); + + // + + // + if (count($rdata) > 0) { + + $this->rendezvous_servers = preg_replace('/\.$/', '', $rdata); + } + + // + + // + $this->hit_length = strlen(pack('H*', $this->hit)); + $this->pk_length = strlen(base64_decode($this->public_key)); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Chit_length/Cpk_algorithm/npk_length', $this->rdata); + + $this->hit_length = $x['hit_length']; + $this->pk_algorithm = $x['pk_algorithm']; + $this->pk_length = $x['pk_length']; + + $offset = 4; + + // + + // + $hit = unpack('H*', substr($this->rdata, $offset, $this->hit_length)); + + $this->hit = strtoupper($hit[1]); + $offset += $this->hit_length; + + // + + // + $this->public_key = base64_encode( + substr($this->rdata, $offset, $this->pk_length) + ); + $offset += $this->pk_length; + + // + + // + $offset = $packet->offset + $offset; + + while ( ($offset - $packet->offset) < $this->rdlength) { + + $this->rendezvous_servers[] = Net_DNS2_Packet::expand( + $packet, $offset + ); + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if ( (strlen($this->hit) > 0) && (strlen($this->public_key) > 0) ) { + + // + + // + $data = pack( + 'CCnH*', + $this->hit_length, + $this->pk_algorithm, + $this->pk_length, + $this->hit + ); + + // + + // + $data .= base64_decode($this->public_key); + + // + + // + $packet->offset += strlen($data); + + // + + // + foreach ($this->rendezvous_servers as $index => $server) { + + $data .= $packet->compress($server, $packet->offset); + } + + return $data; + } + + return null; + } +} + +?>precedence . ' ' . $this->gateway_type . ' ' . + $this->algorithm . ' '; + + switch($this->gateway_type) { + case self::GATEWAY_TYPE_NONE: + $out .= '. '; + break; + + case self::GATEWAY_TYPE_IPV4: + case self::GATEWAY_TYPE_IPV6: + $out .= $this->gateway . ' '; + break; + + case self::GATEWAY_TYPE_DOMAIN: + $out .= $this->gateway . '. '; + break; + } + + $out .= $this->key; + return $out; + } + + protected function rrFromString(array $rdata) + { + // + + // + $precedence = array_shift($rdata); + $gateway_type = array_shift($rdata); + $algorithm = array_shift($rdata); + $gateway = strtolower(trim(array_shift($rdata))); + $key = array_shift($rdata); + + // + + // + switch($gateway_type) { + case self::GATEWAY_TYPE_NONE: + $gateway = ''; + break; + + case self::GATEWAY_TYPE_IPV4: + if (Net_DNS2::isIPv4($gateway) == false) { + return false; + } + break; + + case self::GATEWAY_TYPE_IPV6: + if (Net_DNS2::isIPv6($gateway) == false) { + return false; + } + break; + + case self::GATEWAY_TYPE_DOMAIN: + ; + break; + + default: + return false; + } + + // + + // + switch($algorithm) { + case self::ALGORITHM_NONE: + $key = ''; + break; + + case self::ALGORITHM_DSA: + case self::ALGORITHM_RSA: + ; + break; + + default: + return false; + } + + // + + // + $this->precedence = $precedence; + $this->gateway_type = $gateway_type; + $this->algorithm = $algorithm; + $this->gateway = $gateway; + $this->key = $key; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Cprecedence/Cgateway_type/Calgorithm', $this->rdata); + + $this->precedence = $x['precedence']; + $this->gateway_type = $x['gateway_type']; + $this->algorithm = $x['algorithm']; + + $offset = 3; + + // + + // + switch($this->gateway_type) { + case self::GATEWAY_TYPE_NONE: + $this->gateway = ''; + break; + + case self::GATEWAY_TYPE_IPV4: + $this->gateway = inet_ntop(substr($this->rdata, $offset, 4)); + $offset += 4; + break; + + case self::GATEWAY_TYPE_IPV6: + $ip = unpack('n8', substr($this->rdata, $offset, 16)); + if (count($ip) == 8) { + + $this->gateway = vsprintf('%x:%x:%x:%x:%x:%x:%x:%x', $ip); + $offset += 16; + } else { + + return false; + } + break; + + case self::GATEWAY_TYPE_DOMAIN: + + $doffset = $offset + $packet->offset; + $this->gateway = Net_DNS2_Packet::expand($packet, $doffset); + $offset = ($doffset - $packet->offset); + break; + + default: + return false; + } + + // + + // + switch($this->algorithm) { + case self::ALGORITHM_NONE: + $this->key = ''; + break; + + case self::ALGORITHM_DSA: + case self::ALGORITHM_RSA: + $this->key = base64_encode(substr($this->rdata, $offset)); + break; + + default: + return false; + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + // + + // + $data = pack( + 'CCC', $this->precedence, $this->gateway_type, $this->algorithm + ); + + // + + // + switch($this->gateway_type) { + case self::GATEWAY_TYPE_NONE: + ; + break; + + case self::GATEWAY_TYPE_IPV4: + case self::GATEWAY_TYPE_IPV6: + $data .= inet_pton($this->gateway); + break; + + case self::GATEWAY_TYPE_DOMAIN: + $data .= chr(strlen($this->gateway)) . $this->gateway; + break; + + default: + return null; + } + + // + + // + switch($this->algorithm) { + case self::ALGORITHM_NONE: + ; + break; + + case self::ALGORITHM_DSA: + case self::ALGORITHM_RSA: + $data .= base64_decode($this->key); + break; + + default: + return null; + } + + $packet->offset += strlen($data); + + return $data; + } +} + +?>formatString($this->isdnaddress) . ' ' . + $this->formatString($this->sa); + } + + protected function rrFromString(array $rdata) + { + $data = $this->buildString($rdata); + if (count($data) >= 1) { + + $this->isdnaddress = $data[0]; + if (isset($data[1])) { + + $this->sa = $data[1]; + } + + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $this->isdnaddress = Net_DNS2_Packet::label($packet, $packet->offset); + + // + + // + if ( (strlen($this->isdnaddress) + 1) < $this->rdlength) { + + $this->sa = Net_DNS2_Packet::label($packet, $packet->offset); + } else { + + $this->sa = ''; + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->isdnaddress) > 0) { + + $data = chr(strlen($this->isdnaddress)) . $this->isdnaddress; + if (!empty($this->sa)) { + + $data .= chr(strlen($this->sa)); + $data .= $this->sa; + } + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>preference . ' ' . $this->cleanString($this->exchange) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->preference = array_shift($rdata); + $this->exchange = $this->cleanString(array_shift($rdata)); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference', $this->rdata); + $this->preference = $x['preference']; + + // + + // + $offset = $packet->offset + 2; + $this->exchange = Net_DNS2_Packet::label($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->exchange) > 0) { + + $data = pack('nC', $this->preference, strlen($this->exchange)) . + $this->exchange; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>preference . ' ' . $this->locator32; + } + + protected function rrFromString(array $rdata) + { + $this->preference = array_shift($rdata); + $this->locator32 = array_shift($rdata); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference/C4locator', $this->rdata); + + $this->preference = $x['preference']; + + // + + // + $this->locator32 = $x['locator1'] . '.' . $x['locator2'] . '.' . + $x['locator3'] . '.' . $x['locator4']; + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->locator32) > 0) { + + // + + // + $n = explode('.', $this->locator32); + + // + + // + return pack('nC4', $this->preference, $n[0], $n[1], $n[2], $n[3]); + } + + return null; + } +} + +?>preference . ' ' . $this->locator64; + } + + protected function rrFromString(array $rdata) + { + $this->preference = array_shift($rdata); + $this->locator64 = array_shift($rdata); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference/n4locator', $this->rdata); + + $this->preference = $x['preference']; + + // + + // + $this->locator64 = dechex($x['locator1']) . ':' . + dechex($x['locator2']) . ':' . + dechex($x['locator3']) . ':' . + dechex($x['locator4']); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->locator64) > 0) { + + // + + // + $n = explode(':', $this->locator64); + + // + + // + return pack( + 'n5', $this->preference, hexdec($n[0]), hexdec($n[1]), + hexdec($n[2]), hexdec($n[3]) + ); + } + + return null; + } +} + +?>version == 0) { + + return $this->_d2Dms($this->latitude, 'LAT') . ' ' . + $this->_d2Dms($this->longitude, 'LNG') . ' ' . + sprintf('%.2fm', $this->altitude) . ' ' . + sprintf('%.2fm', $this->size) . ' ' . + sprintf('%.2fm', $this->horiz_pre) . ' ' . + sprintf('%.2fm', $this->vert_pre); + } + + return ''; + } + + protected function rrFromString(array $rdata) + { + // + + // + + // + $res = preg_match( + '/^(\d+) \s+((\d+) \s+)?(([\d.]+) \s+)?(N|S) \s+(\d+) ' . + '\s+((\d+) \s+)?(([\d.]+) \s+)?(E|W) \s+(-?[\d.]+) m?(\s+ ' . + '([\d.]+) m?)?(\s+ ([\d.]+) m?)?(\s+ ([\d.]+) m?)?/ix', + implode(' ', $rdata), $x + ); + + if ($res) { + + // + + // + $latdeg = $x[1]; + $latmin = (isset($x[3])) ? $x[3] : 0; + $latsec = (isset($x[5])) ? $x[5] : 0; + $lathem = strtoupper($x[6]); + + $this->latitude = $this->_dms2d($latdeg, $latmin, $latsec, $lathem); + + // + + // + $londeg = $x[7]; + $lonmin = (isset($x[9])) ? $x[9] : 0; + $lonsec = (isset($x[11])) ? $x[11] : 0; + $lonhem = strtoupper($x[12]); + + $this->longitude = $this->_dms2d($londeg, $lonmin, $lonsec, $lonhem); + + // + + // + $version = 0; + + $this->size = (isset($x[15])) ? $x[15] : 1; + $this->horiz_pre = ((isset($x[17])) ? $x[17] : 10000); + $this->vert_pre = ((isset($x[19])) ? $x[19] : 10); + $this->altitude = $x[13]; + + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack( + 'Cver/Csize/Choriz_pre/Cvert_pre/Nlatitude/Nlongitude/Naltitude', + $this->rdata + ); + + // + + // + $this->version = $x['ver']; + if ($this->version == 0) { + + $this->size = $this->_precsizeNtoA($x['size']); + $this->horiz_pre = $this->_precsizeNtoA($x['horiz_pre']); + $this->vert_pre = $this->_precsizeNtoA($x['vert_pre']); + + // + + // + if ($x['latitude'] < 0) { + + $this->latitude = ($x['latitude'] + + self::REFERENCE_LATLON) / self::CONV_DEG; + } else { + + $this->latitude = ($x['latitude'] - + self::REFERENCE_LATLON) / self::CONV_DEG; + } + + if ($x['longitude'] < 0) { + + $this->longitude = ($x['longitude'] + + self::REFERENCE_LATLON) / self::CONV_DEG; + } else { + + $this->longitude = ($x['longitude'] - + self::REFERENCE_LATLON) / self::CONV_DEG; + } + + // + + // + $this->altitude = ($x['altitude'] - self::REFERENCE_ALT) / 100; + + return true; + + } else { + + return false; + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if ($this->version == 0) { + + $lat = 0; + $lng = 0; + + if ($this->latitude < 0) { + + $lat = ($this->latitude * self::CONV_DEG) - self::REFERENCE_LATLON; + } else { + + $lat = ($this->latitude * self::CONV_DEG) + self::REFERENCE_LATLON; + } + + if ($this->longitude < 0) { + + $lng = ($this->longitude * self::CONV_DEG) - self::REFERENCE_LATLON; + } else { + + $lng = ($this->longitude * self::CONV_DEG) + self::REFERENCE_LATLON; + } + + $packet->offset += 16; + + return pack( + 'CCCCNNN', + $this->version, + $this->_precsizeAtoN($this->size), + $this->_precsizeAtoN($this->horiz_pre), + $this->_precsizeAtoN($this->vert_pre), + $lat, $lng, + ($this->altitude * 100) + self::REFERENCE_ALT + ); + } + + return null; + } + + private function _precsizeNtoA($prec) + { + $mantissa = (($prec >> 4) & 0x0f) % 10; + $exponent = (($prec >> 0) & 0x0f) % 10; + + return $mantissa * $this->_powerOfTen[$exponent]; + } + + private function _precsizeAtoN($prec) + { + $exponent = 0; + while ($prec >= 10) { + + $prec /= 10; + ++$exponent; + } + + return ($prec << 4) | ($exponent & 0x0f); + } + + private function _dms2d($deg, $min, $sec, $hem) + { + $deg = $deg - 0; + $min = $min - 0; + + $sign = ($hem == 'W' || $hem == 'S') ? -1 : 1; + return ((($sec/60+$min)/60)+$deg) * $sign; + } + + private function _d2Dms($data, $latlng) + { + $deg = 0; + $min = 0; + $sec = 0; + $msec = 0; + $hem = ''; + + if ($latlng == 'LAT') { + $hem = ($data > 0) ? 'N' : 'S'; + } else { + $hem = ($data > 0) ? 'E' : 'W'; + } + + $data = abs($data); + + $deg = (int)$data; + $min = (int)(($data - $deg) * 60); + $sec = (int)(((($data - $deg) * 60) - $min) * 60); + $msec = round((((((($data - $deg) * 60) - $min) * 60) - $sec) * 1000)); + + return sprintf('%d %02d %02d.%03d %s', $deg, $min, $sec, round($msec), $hem); + } +} + +?>preference . ' ' . $this->fqdn . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->preference = array_shift($rdata); + $this->fqdn = trim(array_shift($rdata), '.'); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference', $this->rdata); + $this->preference = $x['preference']; + $offset = $packet->offset + 2; + + // + + // + $this->fqdn = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->fqdn) > 0) { + + $data = pack('n', $this->preference); + $packet->offset += 2; + + $data .= $packet->compress($this->fqdn, $packet->offset); + return $data; + } + + return null; + } +} + +?>preference . ' ' . $this->cleanString($this->exchange) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->preference = array_shift($rdata); + $this->exchange = $this->cleanString(array_shift($rdata)); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference', $this->rdata); + $this->preference = $x['preference']; + + // + + // + $offset = $packet->offset + 2; + $this->exchange = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->exchange) > 0) { + + $data = pack('n', $this->preference); + $packet->offset += 2; + + $data .= $packet->compress($this->exchange, $packet->offset); + return $data; + } + + return null; + } +} + +?>order . ' ' . $this->preference . ' ' . + $this->formatString($this->flags) . ' ' . + $this->formatString($this->services) . ' ' . + $this->formatString($this->regexp) . ' ' . + $this->cleanString($this->replacement) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->order = array_shift($rdata); + $this->preference = array_shift($rdata); + + $data = $this->buildString($rdata); + if (count($data) == 4) { + + $this->flags = $data[0]; + $this->services = $data[1]; + $this->regexp = $data[2]; + $this->replacement = $this->cleanString($data[3]); + + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('norder/npreference', $this->rdata); + + $this->order = $x['order']; + $this->preference = $x['preference']; + + $offset = $packet->offset + 4; + + $this->flags = Net_DNS2_Packet::label($packet, $offset); + $this->services = Net_DNS2_Packet::label($packet, $offset); + $this->regexp = Net_DNS2_Packet::label($packet, $offset); + + $this->replacement = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if ( (isset($this->order)) && (strlen($this->services) > 0) ) { + + $data = pack('nn', $this->order, $this->preference); + + $data .= chr(strlen($this->flags)) . $this->flags; + $data .= chr(strlen($this->services)) . $this->services; + $data .= chr(strlen($this->regexp)) . $this->regexp; + + $packet->offset += strlen($data); + + $data .= $packet->compress($this->replacement, $packet->offset); + + return $data; + } + + return null; + } +} + +?>preference . ' ' . $this->nodeid; + } + + protected function rrFromString(array $rdata) + { + $this->preference = array_shift($rdata); + $this->nodeid = array_shift($rdata); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference/n4nodeid', $this->rdata); + + $this->preference = $x['preference']; + + // + + // + $this->nodeid = dechex($x['nodeid1']) . ':' . + dechex($x['nodeid2']) . ':' . + dechex($x['nodeid3']) . ':' . + dechex($x['nodeid4']); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->nodeid) > 0) { + + // + + // + $n = explode(':', $this->nodeid); + + // + + // + return pack( + 'n5', $this->preference, hexdec($n[0]), hexdec($n[1]), + hexdec($n[2]), hexdec($n[3]) + ); + } + + return null; + } +} + +?>rdata; + } +} + +?>cleanString($this->nsdname) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->nsdname = $this->cleanString(array_shift($rdata)); + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + $this->nsdname = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->nsdname) > 0) { + + return $packet->compress($this->nsdname, $packet->offset); + } + + return null; + } +} + +?>cleanString($this->afi) . '.' . + $this->cleanString($this->idi) . '.' . + $this->cleanString($this->dfi) . '.' . + $this->cleanString($this->aa) . '.' . + $this->cleanString($this->rsvd) . '.' . + $this->cleanString($this->rd) . '.' . + $this->cleanString($this->area) . '.' . + $this->cleanString($this->id) . '.' . + $this->sel; + } + + protected function rrFromString(array $rdata) + { + $data = strtolower(trim(array_shift($rdata))); + + // + + // + $data = str_replace(array('.', '0x'), '', $data); + + // + + // + $x = unpack('A2afi/A4idi/A2dfi/A6aa/A4rsvd/A4rd/A4area/A12id/A2sel', $data); + + // + + // + if ($x['afi'] == 47) { + + $this->afi = '0x' . $x['afi']; + $this->idi = $x['idi']; + $this->dfi = $x['dfi']; + $this->aa = $x['aa']; + $this->rsvd = $x['rsvd']; + $this->rd = $x['rd']; + $this->area = $x['area']; + $this->id = $x['id']; + $this->sel = $x['sel']; + + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength == 20) { + + // + + // + $this->afi = dechex(ord($this->rdata[0])); + + // + + // + if ($this->afi == 47) { + + // + + // + $x = unpack( + 'Cafi/nidi/Cdfi/C3aa/nrsvd/nrd/narea/Nidh/nidl/Csel', + $this->rdata + ); + + $this->afi = sprintf('0x%02x', $x['afi']); + $this->idi = sprintf('%04x', $x['idi']); + $this->dfi = sprintf('%02x', $x['dfi']); + $this->aa = sprintf( + '%06x', $x['aa1'] << 16 | $x['aa2'] << 8 | $x['aa3'] + ); + $this->rsvd = sprintf('%04x', $x['rsvd']); + $this->rd = sprintf('%04x', $x['rd']); + $this->area = sprintf('%04x', $x['area']); + $this->id = sprintf('%08x', $x['idh']) . + sprintf('%04x', $x['idl']); + $this->sel = sprintf('%02x', $x['sel']); + + return true; + } + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if ($this->afi == 0x47) { + + // + + // + $aa = unpack('A2x/A2y/A2z', $this->aa); + + // + + // + $id = unpack('A8a/A4b', $this->id); + + // + $data = pack( + 'CnCCCCnnnNnC', + hexdec($this->afi), + hexdec($this->idi), + hexdec($this->dfi), + hexdec($aa['x']), + hexdec($aa['y']), + hexdec($aa['z']), + hexdec($this->rsvd), + hexdec($this->rd), + hexdec($this->area), + hexdec($id['a']), + hexdec($id['b']), + hexdec($this->sel) + ); + + if (strlen($data) == 20) { + + $packet->offset += 20; + return $data; + } + } + + return null; + } +} + +?>cleanString($this->next_domain_name) . '.'; + + foreach ($this->type_bit_maps as $rr) { + + $data .= ' ' . $rr; + } + + return $data; + } + + protected function rrFromString(array $rdata) + { + $this->next_domain_name = $this->cleanString(array_shift($rdata)); + $this->type_bit_maps = $rdata; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $offset = $packet->offset; + $this->next_domain_name = Net_DNS2_Packet::expand($packet, $offset); + + // + + // + $this->type_bit_maps = Net_DNS2_BitMap::bitMapToArray( + substr($this->rdata, $offset - $packet->offset) + ); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->next_domain_name) > 0) { + + $data = $packet->compress($this->next_domain_name, $packet->offset); + $bitmap = Net_DNS2_BitMap::arrayToBitMap($this->type_bit_maps); + + $packet->offset += strlen($bitmap); + + return $data . $bitmap; + } + + return null; + } +} + +?>algorithm . ' ' . $this->flags . ' ' . $this->iterations . ' '; + + // + + // + if ($this->salt_length > 0) { + + $out .= $this->salt; + } else { + + $out .= '-'; + } + + // + + // + $out .= ' ' . $this->hashed_owner_name; + + // + + // + foreach ($this->type_bit_maps as $rr) { + + $out .= ' ' . strtoupper($rr); + } + + return $out; + } + + protected function rrFromString(array $rdata) + { + $this->algorithm = array_shift($rdata); + $this->flags = array_shift($rdata); + $this->iterations = array_shift($rdata); + + // + + // + $salt = array_shift($rdata); + if ($salt == '-') { + + $this->salt_length = 0; + $this->salt = ''; + } else { + + $this->salt_length = strlen(pack('H*', $salt)); + $this->salt = strtoupper($salt); + } + + $this->hashed_owner_name = array_shift($rdata); + $this->hash_length = strlen(base64_decode($this->hashed_owner_name)); + + $this->type_bit_maps = $rdata; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Calgorithm/Cflags/niterations/Csalt_length', $this->rdata); + + $this->algorithm = $x['algorithm']; + $this->flags = $x['flags']; + $this->iterations = $x['iterations']; + $this->salt_length = $x['salt_length']; + + $offset = 5; + + if ($this->salt_length > 0) { + + $x = unpack('H*', substr($this->rdata, $offset, $this->salt_length)); + $this->salt = strtoupper($x[1]); + $offset += $this->salt_length; + } + + // + + // + $x = unpack('@' . $offset . '/Chash_length', $this->rdata); + $offset++; + + // + + // + $this->hash_length = $x['hash_length']; + if ($this->hash_length > 0) { + + $this->hashed_owner_name = base64_encode( + substr($this->rdata, $offset, $this->hash_length) + ); + $offset += $this->hash_length; + } + + // + + // + $this->type_bit_maps = Net_DNS2_BitMap::bitMapToArray( + substr($this->rdata, $offset) + ); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + // + + // + $salt = pack('H*', $this->salt); + $this->salt_length = strlen($salt); + + // + + // + $data = pack( + 'CCnC', + $this->algorithm, $this->flags, $this->iterations, $this->salt_length + ); + $data .= $salt; + + // + + // + $data .= chr($this->hash_length); + if ($this->hash_length > 0) { + + $data .= base64_decode($this->hashed_owner_name); + } + + // + + // + $data .= Net_DNS2_BitMap::arrayToBitMap($this->type_bit_maps); + + $packet->offset += strlen($data); + + return $data; + } +} + +?>algorithm . ' ' . $this->flags . ' ' . $this->iterations . ' '; + + // + + // + if ($this->salt_length > 0) { + + $out .= $this->salt; + } else { + + $out .= '-'; + } + + return $out; + } + + protected function rrFromString(array $rdata) + { + $this->algorithm = array_shift($rdata); + $this->flags = array_shift($rdata); + $this->iterations = array_shift($rdata); + + $salt = array_shift($rdata); + if ($salt == '-') { + + $this->salt_length = 0; + $this->salt = ''; + } else { + + $this->salt_length = strlen(pack('H*', $salt)); + $this->salt = strtoupper($salt); + } + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $x = unpack('Calgorithm/Cflags/niterations/Csalt_length', $this->rdata); + + $this->algorithm = $x['algorithm']; + $this->flags = $x['flags']; + $this->iterations = $x['iterations']; + $this->salt_length = $x['salt_length']; + + if ($this->salt_length > 0) { + + $x = unpack('H*', substr($this->rdata, 5, $this->salt_length)); + $this->salt = strtoupper($x[1]); + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $salt = pack('H*', $this->salt); + $this->salt_length = strlen($salt); + + $data = pack( + 'CCnC', + $this->algorithm, $this->flags, $this->iterations, $this->salt_length + ) . $salt; + + $packet->offset += strlen($data); + + return $data; + } +} + +?>key; + } + + protected function rrFromString(array $rdata) + { + $this->key = array_shift($rdata); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $this->key = base64_encode($this->rdata); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->key) > 0) { + + $data = base64_decode($this->key); + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>type = 'OPT'; + $this->rdlength = 0; + + $this->option_length = 0; + $this->extended_rcode = 0; + $this->version = 0; + $this->do = 0; + $this->z = 0; + + // + + // + if ( (!is_null($packet)) && (!is_null($rr)) ) { + + parent::__construct($packet, $rr); + } + } + + protected function rrToString() + { + return $this->option_code . ' ' . $this->option_data; + } + + protected function rrFromString(array $rdata) + { + $this->option_code = array_shift($rdata); + $this->option_data = array_shift($rdata); + $this->option_length = strlen($this->option_data); + + $x = unpack('Cextended/Cversion/Cdo/Cz', pack('N', $this->ttl)); + + $this->extended_rcode = $x['extended']; + $this->version = $x['version']; + $this->do = ($x['do'] >> 7); + $this->z = $x['z']; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + // + + // + $x = unpack('Cextended/Cversion/Cdo/Cz', pack('N', $this->ttl)); + + $this->extended_rcode = $x['extended']; + $this->version = $x['version']; + $this->do = ($x['do'] >> 7); + $this->z = $x['z']; + + // + + // + if ($this->rdlength > 0) { + + // + + // + $x = unpack('noption_code/noption_length', $this->rdata); + + $this->option_code = $x['option_code']; + $this->option_length = $x['option_length']; + + // + + // + $this->option_data = substr($this->rdata, 4); + } + + return true; + } + + protected function preBuild() + { + // + + // + $ttl = unpack( + 'N', + pack('CCCC', $this->extended_rcode, $this->version, ($this->do << 7), 0) + ); + + $this->ttl = $ttl[1]; + + return; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + // + + // + if ($this->option_code) { + + $data = pack('nn', $this->option_code, $this->option_length) . + $this->option_data; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>ptrdname, '.') . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->ptrdname = rtrim(implode(' ', $rdata), '.'); + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + $this->ptrdname = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->ptrdname) > 0) { + + return $packet->compress($this->ptrdname, $packet->offset); + } + + return null; + } +} + +?>preference . ' ' . $this->cleanString($this->map822) . '. ' . + $this->cleanString($this->mapx400) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->preference = $rdata[0]; + $this->map822 = $this->cleanString($rdata[1]); + $this->mapx400 = $this->cleanString($rdata[2]); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference', $this->rdata); + $this->preference = $x['preference']; + + $offset = $packet->offset + 2; + + $this->map822 = Net_DNS2_Packet::expand($packet, $offset); + $this->mapx400 = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->map822) > 0) { + + $data = pack('n', $this->preference); + $packet->offset += 2; + + $data .= $packet->compress($this->map822, $packet->offset); + $data .= $packet->compress($this->mapx400, $packet->offset); + + return $data; + } + + return null; + } +} + +?>cleanString($this->mboxdname) . '. ' . + $this->cleanString($this->txtdname) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->mboxdname = $this->cleanString($rdata[0]); + $this->txtdname = $this->cleanString($rdata[1]); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + + $this->mboxdname = Net_DNS2_Packet::expand($packet, $offset); + $this->txtdname = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->mboxdname) > 0) { + + return $packet->compress($this->mboxdname, $packet->offset) . + $packet->compress($this->txtdname, $packet->offset); + } + + return null; + } +} + +?>typecovered . ' ' . $this->algorithm . ' ' . + $this->labels . ' ' . $this->origttl . ' ' . + $this->sigexp . ' ' . $this->sigincep . ' ' . + $this->keytag . ' ' . $this->cleanString($this->signname) . '. ' . + $this->signature; + } + + protected function rrFromString(array $rdata) + { + $this->typecovered = strtoupper(array_shift($rdata)); + $this->algorithm = array_shift($rdata); + $this->labels = array_shift($rdata); + $this->origttl = array_shift($rdata); + $this->sigexp = array_shift($rdata); + $this->sigincep = array_shift($rdata); + $this->keytag = array_shift($rdata); + $this->signname = $this->cleanString(array_shift($rdata)); + + foreach ($rdata as $line) { + + $this->signature .= $line; + } + + $this->signature = trim($this->signature); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack( + 'ntc/Calgorithm/Clabels/Norigttl/Nsigexp/Nsigincep/nkeytag', + $this->rdata + ); + + $this->typecovered = Net_DNS2_Lookups::$rr_types_by_id[$x['tc']]; + $this->algorithm = $x['algorithm']; + $this->labels = $x['labels']; + $this->origttl = Net_DNS2::expandUint32($x['origttl']); + + // + + // + $this->sigexp = gmdate('YmdHis', $x['sigexp']); + $this->sigincep = gmdate('YmdHis', $x['sigincep']); + + // + + // + $this->keytag = $x['keytag']; + + // + + // + $offset = $packet->offset + 18; + $sigoffset = $offset; + + $this->signname = strtolower( + Net_DNS2_Packet::expand($packet, $sigoffset) + ); + $this->signature = base64_encode( + substr($this->rdata, 18 + ($sigoffset - $offset)) + ); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->signature) > 0) { + + // + + // + preg_match( + '/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', $this->sigexp, $e + ); + preg_match( + '/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', $this->sigincep, $i + ); + + // + + // + $data = pack( + 'nCCNNNn', + Net_DNS2_Lookups::$rr_types_by_name[$this->typecovered], + $this->algorithm, + $this->labels, + $this->origttl, + gmmktime($e[4], $e[5], $e[6], $e[2], $e[3], $e[1]), + gmmktime($i[4], $i[5], $i[6], $i[2], $i[3], $i[1]), + $this->keytag + ); + + // + + // + $names = explode('.', strtolower($this->signname)); + foreach ($names as $name) { + + $data .= chr(strlen($name)); + $data .= $name; + } + $data .= "\0"; + + // + + // + $data .= base64_decode($this->signature); + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>preference . ' ' . + $this->cleanString($this->intermediatehost) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->preference = $rdata[0]; + $this->intermediatehost = $this->cleanString($rdata[1]); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npreference', $this->rdata); + + $this->preference = $x['preference']; + $offset = $packet->offset + 2; + + $this->intermediatehost = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->intermediatehost) > 0) { + + $data = pack('n', $this->preference); + $packet->offset += 2; + + $data .= $packet->compress($this->intermediatehost, $packet->offset); + + return $data; + } + + return null; + } +} + +?>typecovered . ' ' . $this->algorithm . ' ' . + $this->labels . ' ' . $this->origttl . ' ' . + $this->sigexp . ' ' . $this->sigincep . ' ' . + $this->keytag . ' ' . $this->cleanString($this->signname) . '. ' . + $this->signature; + } + + protected function rrFromString(array $rdata) + { + $this->typecovered = strtoupper(array_shift($rdata)); + $this->algorithm = array_shift($rdata); + $this->labels = array_shift($rdata); + $this->origttl = array_shift($rdata); + $this->sigexp = array_shift($rdata); + $this->sigincep = array_shift($rdata); + $this->keytag = array_shift($rdata); + $this->signname = $this->cleanString(array_shift($rdata)); + + foreach ($rdata as $line) { + + $this->signature .= $line; + } + + $this->signature = trim($this->signature); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack( + 'ntc/Calgorithm/Clabels/Norigttl/Nsigexp/Nsigincep/nkeytag', + $this->rdata + ); + + $this->typecovered = Net_DNS2_Lookups::$rr_types_by_id[$x['tc']]; + $this->algorithm = $x['algorithm']; + $this->labels = $x['labels']; + $this->origttl = Net_DNS2::expandUint32($x['origttl']); + + // + + // + $this->sigexp = gmdate('YmdHis', $x['sigexp']); + $this->sigincep = gmdate('YmdHis', $x['sigincep']); + + // + + // + $this->keytag = $x['keytag']; + + // + + // + $offset = $packet->offset + 18; + $sigoffset = $offset; + + $this->signname = strtolower( + Net_DNS2_Packet::expand($packet, $sigoffset) + ); + $this->signature = base64_encode( + substr($this->rdata, 18 + ($sigoffset - $offset)) + ); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + // + + // + preg_match( + '/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', $this->sigexp, $e + ); + preg_match( + '/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', $this->sigincep, $i + ); + + // + + // + $data = pack( + 'nCCNNNn', + Net_DNS2_Lookups::$rr_types_by_name[$this->typecovered], + $this->algorithm, + $this->labels, + $this->origttl, + gmmktime($e[4], $e[5], $e[6], $e[2], $e[3], $e[1]), + gmmktime($i[4], $i[5], $i[6], $i[2], $i[3], $i[1]), + $this->keytag + ); + + // + + // + $names = explode('.', strtolower($this->signname)); + foreach ($names as $name) { + + $data .= chr(strlen($name)); + $data .= $name; + } + + $data .= chr('0'); + + // + + // + if ( (strlen($this->signature) == 0) + && ($this->private_key instanceof Net_DNS2_PrivateKey) + && (extension_loaded('openssl') === true) + ) { + + // + + // + $new_packet = new Net_DNS2_Packet_Request('example.com', 'SOA', 'IN'); + + // + + // + $new_packet->copy($packet); + + // + + // + array_pop($new_packet->additional); + $new_packet->header->arcount = count($new_packet->additional); + + // + + // + $sigdata = $data . $new_packet->get(); + + // + + // + $algorithm = 0; + + switch($this->algorithm) { + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5: + + $algorithm = OPENSSL_ALGO_MD5; + break; + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1: + + $algorithm = OPENSSL_ALGO_SHA1; + break; + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256: + + if (version_compare(PHP_VERSION, '5.4.8', '<') == true) { + + throw new Net_DNS2_Exception( + 'SHA256 support is only available in PHP >= 5.4.8', + Net_DNS2_Lookups::E_OPENSSL_INV_ALGO + ); + } + + $algorithm = OPENSSL_ALGO_SHA256; + break; + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512: + + if (version_compare(PHP_VERSION, '5.4.8', '<') == true) { + + throw new Net_DNS2_Exception( + 'SHA512 support is only available in PHP >= 5.4.8', + Net_DNS2_Lookups::E_OPENSSL_INV_ALGO + ); + } + + $algorithm = OPENSSL_ALGO_SHA512; + break; + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSA: + case Net_DNS2_Lookups::DSNSEC_ALGORITHM_RSASHA1NSEC3SHA1: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSANSEC3SHA1: + default: + throw new Net_DNS2_Exception( + 'invalid or unsupported algorithm', + Net_DNS2_Lookups::E_OPENSSL_INV_ALGO + ); + break; + } + + // + + // + if (openssl_sign($sigdata, $this->signature, $this->private_key->instance, $algorithm) == false) { + + throw new Net_DNS2_Exception( + openssl_error_string(), + Net_DNS2_Lookups::E_OPENSSL_ERROR + ); + } + + // + + // + switch($this->algorithm) { + + // + + // + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256: + case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512: + + $this->signature = base64_encode($this->signature); + break; + } + } + + // + + // + $data .= base64_decode($this->signature); + + $packet->offset += strlen($data); + + return $data; + } +} + +?>cleanString($this->mname) . '. ' . + $this->cleanString($this->rname) . '. ' . + $this->serial . ' ' . $this->refresh . ' ' . $this->retry . ' ' . + $this->expire . ' ' . $this->minimum; + } + + protected function rrFromString(array $rdata) + { + $this->mname = $this->cleanString($rdata[0]); + $this->rname = $this->cleanString($rdata[1]); + + $this->serial = $rdata[2]; + $this->refresh = $rdata[3]; + $this->retry = $rdata[4]; + $this->expire = $rdata[5]; + $this->minimum = $rdata[6]; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $offset = $packet->offset; + + $this->mname = Net_DNS2_Packet::expand($packet, $offset); + $this->rname = Net_DNS2_Packet::expand($packet, $offset); + + // + + // + $x = unpack( + '@' . $offset . '/Nserial/Nrefresh/Nretry/Nexpire/Nminimum/', + $packet->rdata + ); + + $this->serial = Net_DNS2::expandUint32($x['serial']); + $this->refresh = Net_DNS2::expandUint32($x['refresh']); + $this->retry = Net_DNS2::expandUint32($x['retry']); + $this->expire = Net_DNS2::expandUint32($x['expire']); + $this->minimum = Net_DNS2::expandUint32($x['minimum']); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->mname) > 0) { + + $data = $packet->compress($this->mname, $packet->offset); + $data .= $packet->compress($this->rname, $packet->offset); + + $data .= pack( + 'N5', $this->serial, $this->refresh, $this->retry, + $this->expire, $this->minimum + ); + + $packet->offset += 20; + + return $data; + } + + return null; + } +} + +?>priority . ' ' . $this->weight . ' ' . + $this->port . ' ' . $this->cleanString($this->target) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->priority = $rdata[0]; + $this->weight = $rdata[1]; + $this->port = $rdata[2]; + + $this->target = $this->cleanString($rdata[3]); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npriority/nweight/nport', $this->rdata); + + $this->priority = $x['priority']; + $this->weight = $x['weight']; + $this->port = $x['port']; + + $offset = $packet->offset + 6; + $this->target = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->target) > 0) { + + $data = pack('nnn', $this->priority, $this->weight, $this->port); + $packet->offset += 6; + + $data .= $packet->compress($this->target, $packet->offset); + + return $data; + } + + return null; + } +} + +?>algorithm . ' ' . $this->fp_type . ' ' . $this->fingerprint; + } + + protected function rrFromString(array $rdata) + { + // + + // + + // + $algorithm = array_shift($rdata); + $fp_type = array_shift($rdata); + $fingerprint = strtolower(implode('', $rdata)); + + // + + // + if ( ($algorithm != self::SSHFP_ALGORITHM_RSA) + && ($algorithm != self::SSHFP_ALGORITHM_DSS) + ) { + return false; + } + + // + + // + if ($fp_type != self::SSHFP_FPTYPE_SHA1) { + return false; + } + + $this->algorithm = $algorithm; + $this->fp_type = $fp_type; + $this->fingerprint = $fingerprint; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Calgorithm/Cfp_type', $this->rdata); + + $this->algorithm = $x['algorithm']; + $this->fp_type = $x['fp_type']; + + // + + // + if ( ($this->algorithm != self::SSHFP_ALGORITHM_RSA) + && ($this->algorithm != self::SSHFP_ALGORITHM_DSS) + ) { + return false; + } + + // + + // + if ($this->fp_type != self::SSHFP_FPTYPE_SHA1) { + return false; + } + + // + + // + $fp = unpack('H*a', substr($this->rdata, 2)); + $this->fingerprint = strtolower($fp['a']); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->fingerprint) > 0) { + + $data = pack( + 'CCH*', $this->algorithm, $this->fp_type, $this->fingerprint + ); + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>cleanString($this->previous) . '. ' . + $this->cleanString($this->next) . '.'; + } + + protected function rrFromString(array $rdata) + { + $this->previous = $this->cleanString($rdata[0]); + $this->next = $this->cleanString($rdata[1]); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $offset = $packet->offset; + + $this->previous = Net_DNS2_Packet::label($packet, $offset); + $this->next = Net_DNS2_Packet::label($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if ( (strlen($this->previous) > 0) || (strlen($this->next) > 0) ) { + + $data = chr(strlen($this->previous)) . $this->previous . + chr(strlen($this->next)) . $this->next; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?> 'Reserved', + self::TSIG_MODE_SERV_ASSIGN => 'Server Assignment', + self::TSIG_MODE_DH => 'Diffie-Hellman', + self::TSIG_MODE_GSS_API => 'GSS-API', + self::TSIG_MODE_RESV_ASSIGN => 'Resolver Assignment', + self::TSIG_MODE_KEY_DELE => 'Key Deletion' + ); + + protected function rrToString() + { + $out = $this->cleanString($this->algorithm) . '. ' . $this->mode; + if ($this->key_size > 0) { + + $out .= ' ' . trim($this->key_data, '.') . '.'; + } else { + + $out .= ' .'; + } + + return $out; + } + + protected function rrFromString(array $rdata) + { + // + + // + $this->algorithm = $this->cleanString(array_shift($rdata)); + $this->mode = array_shift($rdata); + $this->key_data = trim(array_shift($rdata), '.'); + + // + + // + $this->inception = time(); + $this->expiration = time() + 86400; + $this->error = 0; + $this->key_size = strlen($this->key_data); + $this->other_size = 0; + $this->other_data = ''; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $offset = $packet->offset; + $this->algorithm = Net_DNS2_Packet::expand($packet, $offset); + + // + + // + $x = unpack( + '@' . $offset . '/Ninception/Nexpiration/nmode/nerror/nkey_size', + $packet->rdata + ); + + $this->inception = Net_DNS2::expandUint32($x['inception']); + $this->expiration = Net_DNS2::expandUint32($x['expiration']); + $this->mode = $x['mode']; + $this->error = $x['error']; + $this->key_size = $x['key_size']; + + $offset += 14; + + // + + // + if ($this->key_size > 0) { + + $this->key_data = substr($packet->rdata, $offset, $this->key_size); + $offset += $this->key_size; + } + + // + + // + $x = unpack('@' . $offset . '/nother_size', $packet->rdata); + + $this->other_size = $x['other_size']; + $offset += 2; + + // + + // + if ($this->other_size > 0) { + + $this->other_data = substr( + $packet->rdata, $offset, $this->other_size + ); + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->algorithm) > 0) { + + // + + // + $this->key_size = strlen($this->key_data); + $this->other_size = strlen($this->other_data); + + // + + // + $data = Net_DNS2_Packet::pack($this->algorithm); + + // + + // + $data .= pack( + 'NNnnn', $this->inception, $this->expiration, + $this->mode, 0, $this->key_size + ); + + // + + // + if ($this->key_size > 0) { + + $data .= $this->key_data; + } + + // + + // + $data .= pack('n', $this->other_size); + if ($this->other_size > 0) { + + $data .= $this->other_data; + } + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>cert_usage . ' ' . $this->selector . ' ' . + $this->matching_type . ' ' . base64_encode($this->certificate); + } + + protected function rrFromString(array $rdata) + { + $this->cert_usage = array_shift($rdata); + $this->selector = array_shift($rdata); + $this->matching_type = array_shift($rdata); + $this->certificate = base64_decode(implode('', $rdata)); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Cusage/Cselector/Ctype', $this->rdata); + + $this->cert_usage = $x['usage']; + $this->selector = $x['selector']; + $this->matching_type = $x['type']; + + // + + // + $this->certificate = substr($this->rdata, 3, $this->rdlength - 3); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->certificate) > 0) { + + $data = pack( + 'CCC', $this->cert_usage, $this->selector, $this->matching_type + ) . $this->certificate; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?> 'md5', + self::HMAC_SHA1 => 'sha1', + self::HMAC_SHA224 => 'sha224', + self::HMAC_SHA256 => 'sha256', + self::HMAC_SHA384 => 'sha384', + self::HMAC_SHA512 => 'sha512' + ); + + public $algorithm; + + public $time_signed; + + public $fudge; + + public $mac_size; + + public $mac; + + public $original_id; + + public $error; + + public $other_length; + + public $other_data; + + public $key; + + protected function rrToString() + { + $out = $this->cleanString($this->algorithm) . '. ' . + $this->time_signed . ' ' . + $this->fudge . ' ' . $this->mac_size . ' ' . + base64_encode($this->mac) . ' ' . $this->original_id . ' ' . + $this->error . ' '. $this->other_length; + + if ($this->other_length > 0) { + + $out .= ' ' . $this->other_data; + } + + return $out; + } + + protected function rrFromString(array $rdata) + { + // + + // + + // + $this->key = preg_replace('/\s+/', '', array_shift($rdata)); + + // + + // + $this->algorithm = self::HMAC_MD5; + $this->time_signed = time(); + $this->fudge = 300; + $this->mac_size = 0; + $this->mac = ''; + $this->original_id = 0; + $this->error = 0; + $this->other_length = 0; + $this->other_data = ''; + + // + + // + $this->class = 'ANY'; + $this->ttl = 0; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $newoffset = $packet->offset; + $this->algorithm = Net_DNS2_Packet::expand($packet, $newoffset); + $offset = $newoffset - $packet->offset; + + // + + // + $x = unpack( + '@' . $offset . '/ntime_high/Ntime_low/nfudge/nmac_size', + $this->rdata + ); + + $this->time_signed = Net_DNS2::expandUint32($x['time_low']); + $this->fudge = $x['fudge']; + $this->mac_size = $x['mac_size']; + + $offset += 10; + + // + + // + if ($this->mac_size > 0) { + + $this->mac = substr($this->rdata, $offset, $this->mac_size); + $offset += $this->mac_size; + } + + // + + // + $x = unpack( + '@' . $offset . '/noriginal_id/nerror/nother_length', + $this->rdata + ); + + $this->original_id = $x['original_id']; + $this->error = $x['error']; + $this->other_length = $x['other_length']; + + // + + // + + // + if ($this->error == Net_DNS2_Lookups::RCODE_BADTIME) { + + if ($this->other_length != 6) { + + return false; + } + + // + + // + $x = unpack( + 'nhigh/nlow', + substr($this->rdata, $offset + 6, $this->other_length) + ); + $this->other_data = $x['low']; + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->key) > 0) { + + // + + // + $new_packet = new Net_DNS2_Packet_Request('example.com', 'SOA', 'IN'); + + // + + // + $new_packet->copy($packet); + + // + + // + array_pop($new_packet->additional); + $new_packet->header->arcount = count($new_packet->additional); + + // + + // + $sig_data = $new_packet->get(); + + // + + // + $sig_data .= Net_DNS2_Packet::pack($this->name); + + // + + // + $sig_data .= pack( + 'nN', Net_DNS2_Lookups::$classes_by_name[$this->class], $this->ttl + ); + + // + + // + $sig_data .= Net_DNS2_Packet::pack(strtolower($this->algorithm)); + + // + + // + $sig_data .= pack( + 'nNnnn', 0, $this->time_signed, $this->fudge, + $this->error, $this->other_length + ); + if ($this->other_length > 0) { + + $sig_data .= pack('nN', 0, $this->other_data); + } + + // + + // + $this->mac = $this->_signHMAC( + $sig_data, base64_decode($this->key), $this->algorithm + ); + $this->mac_size = strlen($this->mac); + + // + + // + $data = Net_DNS2_Packet::pack(strtolower($this->algorithm)); + + // + + // + $data .= pack( + 'nNnn', 0, $this->time_signed, $this->fudge, $this->mac_size + ); + $data .= $this->mac; + + // + + // + if ($this->error == Net_DNS2_Lookups::RCODE_BADTIME) { + + $this->other_length = strlen($this->other_data); + if ($this->other_length != 6) { + + return null; + } + } else { + + $this->other_length = 0; + $this->other_data = ''; + } + + // + + // + $data .= pack( + 'nnn', $packet->header->id, $this->error, $this->other_length + ); + if ($this->other_length > 0) { + + $data .= pack('nN', 0, $this->other_data); + } + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } + + private function _signHMAC($data, $key = null, $algorithm = self::HMAC_MD5) + { + // + + // + if (extension_loaded('hash')) { + + if (!isset(self::$hash_algorithms[$algorithm])) { + + throw new Net_DNS2_Exception( + 'invalid or unsupported algorithm', + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + + return hash_hmac(self::$hash_algorithms[$algorithm], $data, $key, true); + } + + // + + // + if ($algorithm != self::HMAC_MD5) { + + throw new Net_DNS2_Exception( + 'only HMAC-MD5 supported. please install the php-extension ' . + '"hash" in order to use the sha-family', + Net_DNS2_Lookups::E_PARSE_ERROR + ); + } + + // + + // + if (is_null($key)) { + + return pack('H*', md5($data)); + } + + $key = str_pad($key, 64, chr(0x00)); + if (strlen($key) > 64) { + + $key = pack('H*', md5($key)); + } + + $k_ipad = $key ^ str_repeat(chr(0x36), 64); + $k_opad = $key ^ str_repeat(chr(0x5c), 64); + + return $this->_signHMAC( + $k_opad . pack('H*', md5($k_ipad . $data)), null, $algorithm + ); + } +} + +?>text) == 0) { + return '""'; + } + + $data = ''; + + foreach ($this->text as $t) { + + $data .= $this->formatString($t) . ' '; + } + + return trim($data); + } + + protected function rrFromString(array $rdata) + { + $data = $this->buildString($rdata); + if (count($data) > 0) { + + $this->text = $data; + } + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $length = $packet->offset + $this->rdlength; + $offset = $packet->offset; + + while ($length > $offset) { + + $this->text[] = Net_DNS2_Packet::label($packet, $offset); + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + $data = null; + + foreach ($this->text as $t) { + + $data .= chr(strlen($t)) . $t; + } + + $packet->offset += strlen($data); + + return $data; + } +} + +?>priority . ' ' . $this->weight . ' "' . + $this->cleanString($this->target) . '"'; + } + + protected function rrFromString(array $rdata) + { + $this->priority = $rdata[0]; + $this->weight = $rdata[1]; + + // + + // + $this->target = trim($this->cleanString($rdata[2]), '"'); + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('npriority/nweight', $this->rdata); + + $this->priority = $x['priority']; + $this->weight = $x['weight']; + + $offset = $packet->offset + 4; + $this->target = Net_DNS2_Packet::expand($packet, $offset); + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->target) > 0) { + + $data = pack('nn', $this->priority, $this->weight); + $packet->offset += 4; + + $data .= $packet->compress(trim($this->target, '"'), $packet->offset); + + return $data; + } + + return null; + } +} + +?>address . ' ' . $this->protocol; + + foreach ($this->bitmap as $port) { + $data .= ' ' . $port; + } + + return $data; + } + + protected function rrFromString(array $rdata) + { + $this->address = strtolower(trim(array_shift($rdata), '.')); + $this->protocol = array_shift($rdata); + $this->bitmap = $rdata; + + return true; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + // + + // + $x = unpack('Naddress/Cprotocol', $this->rdata); + + $this->address = long2ip($x['address']); + $this->protocol = $x['protocol']; + + // + + // + $port = 0; + foreach (unpack('@5/C*', $this->rdata) as $set) { + + $s = sprintf('%08b', $set); + + for ($i=0; $i<8; $i++, $port++) { + if ($s[$i] == '1') { + $this->bitmap[] = $port; + } + } + } + + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->address) > 0) { + + $data = pack('NC', ip2long($this->address), $this->protocol); + + $ports = array(); + + $n = 0; + foreach ($this->bitmap as $port) { + $ports[$port] = 1; + + if ($port > $n) { + $n = $port; + } + } + for ($i=0; $ioffset += strlen($data); + + return $data; + } + + return null; + } +} + +?>formatString($this->psdnaddress); + } + + protected function rrFromString(array $rdata) + { + $data = $this->buildString($rdata); + if (count($data) == 1) { + + $this->psdnaddress = $data[0]; + return true; + } + + return false; + } + + protected function rrSet(Net_DNS2_Packet &$packet) + { + if ($this->rdlength > 0) { + + $this->psdnaddress = Net_DNS2_Packet::label($packet, $packet->offset); + return true; + } + + return false; + } + + protected function rrGet(Net_DNS2_Packet &$packet) + { + if (strlen($this->psdnaddress) > 0) { + + $data = chr(strlen($this->psdnaddress)) . $this->psdnaddress; + + $packet->offset += strlen($data); + + return $data; + } + + return null; + } +} + +?>host) == true) { + + $this->sock = @socket_create( + AF_INET, $this->type, + ($this->type == Net_DNS2_Socket::SOCK_STREAM) ? SOL_TCP : SOL_UDP + ); + + } else if (Net_DNS2::isIPv6($this->host) == true) { + + $this->sock = @socket_create( + AF_INET6, $this->type, + ($this->type == Net_DNS2_Socket::SOCK_STREAM) ? SOL_TCP : SOL_UDP + ); + + } else { + + $this->last_error = 'invalid address type: ' . $this->host; + return false; + } + + if ($this->sock === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + + @socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 1); + + // + + // + if (strlen($this->local_host) > 0) { + + $result = @socket_bind( + $this->sock, $this->local_host, + ($this->local_port > 0) ? $this->local_port : null + ); + if ($result === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + } + + // + + // + if (@socket_set_nonblock($this->sock) === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + + // + + // + @socket_connect($this->sock, $this->host, $this->port); + + $read = null; + $write = array($this->sock); + $except = null; + + // + + // + $result = @socket_select($read, $write, $except, $this->timeout); + if ($result === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + + } else if ($result == 0) { + + $this->last_error = 'timeout on write select for connect()'; + return false; + } + + return true; + } + + public function close() + { + if (is_resource($this->sock) === true) { + + @socket_close($this->sock); + } + return true; + } + + public function write($data) + { + $length = strlen($data); + if ($length == 0) { + + $this->last_error = 'empty data on write()'; + return false; + } + + $read = null; + $write = array($this->sock); + $except = null; + + // + + // + $result = @socket_select($read, $write, $except, $this->timeout); + if ($result === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + + } else if ($result == 0) { + + $this->last_error = 'timeout on write select()'; + return false; + } + + // + + // + if ($this->type == Net_DNS2_Socket::SOCK_STREAM) { + + $s = chr($length >> 8) . chr($length); + + if (@socket_write($this->sock, $s) === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + } + + // + + // + $size = @socket_write($this->sock, $data); + if ( ($size === false) || ($size != $length) ) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + + return true; + } + + public function read(&$size, $max_size) + { + $read = array($this->sock); + $write = null; + $except = null; + + // + + // + if (@socket_set_nonblock($this->sock) === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + + // + + // + $result = @socket_select($read, $write, $except, $this->timeout); + if ($result === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + + } else if ($result == 0) { + + $this->last_error = 'timeout on read select()'; + return false; + } + + $data = ''; + $length = $max_size; + + // + + // + if ($this->type == Net_DNS2_Socket::SOCK_STREAM) { + + if (($size = @socket_recv($this->sock, $data, 2, 0)) === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + + $length = ord($data[0]) << 8 | ord($data[1]); + if ($length < Net_DNS2_Lookups::DNS_HEADER_SIZE) { + + return false; + } + } + + // + + // + + // + if (@socket_set_block($this->sock) === false) { + + $this->last_error = socket_strerror(socket_last_error()); + return false; + } + + // + + // + + // + + // + $data = ''; + $size = 0; + + while (1) { + + $chunk_size = @socket_recv($this->sock, $chunk, $length, MSG_WAITALL); + if ($chunk_size === false) { + + $size = $chunk_size; + $this->last_error = socket_strerror(socket_last_error()); + + return false; + } + + $data .= $chunk; + $size += $chunk_size; + + $length -= $chunk_size; + if ( ($length <= 0) || ($this->type == Net_DNS2_Socket::SOCK_DGRAM) ) { + break; + } + } + + return $data; + } +} + +?> array()); + + // + + // + if (strlen($this->local_host) > 0) { + + $opts['socket']['bindto'] = $this->local_host; + if ($this->local_port > 0) { + + $opts['socket']['bindto'] .= ':' . $this->local_port; + } + } + + // + + // + $this->_context = @stream_context_create($opts); + + // + + // + $errno; + $errstr; + + switch($this->type) { + case Net_DNS2_Socket::SOCK_STREAM: + + if (Net_DNS2::isIPv4($this->host) == true) { + + $this->sock = @stream_socket_client( + 'tcp://' . $this->host . ':' . $this->port, + $errno, $errstr, $this->timeout, + STREAM_CLIENT_CONNECT, $this->_context + ); + } else if (Net_DNS2::isIPv6($this->host) == true) { + + $this->sock = @stream_socket_client( + 'tcp://[' . $this->host . ']:' . $this->port, + $errno, $errstr, $this->timeout, + STREAM_CLIENT_CONNECT, $this->_context + ); + } else { + + $this->last_error = 'invalid address type: ' . $this->host; + return false; + } + + break; + + case Net_DNS2_Socket::SOCK_DGRAM: + + if (Net_DNS2::isIPv4($this->host) == true) { + + $this->sock = @stream_socket_client( + 'udp://' . $this->host . ':' . $this->port, + $errno, $errstr, $this->timeout, + STREAM_CLIENT_CONNECT, $this->_context + ); + } else if (Net_DNS2::isIPv6($this->host) == true) { + + $this->sock = @stream_socket_client( + 'udp://[' . $this->host . ']:' . $this->port, + $errno, $errstr, $this->timeout, + STREAM_CLIENT_CONNECT, $this->_context + ); + } else { + + $this->last_error = 'invalid address type: ' . $this->host; + return false; + } + + break; + + default: + $this->last_error = 'Invalid socket type: ' . $this->type; + return false; + } + + if ($this->sock === false) { + + $this->last_error = $errstr; + return false; + } + + // + + // + @stream_set_blocking($this->sock, 0); + @stream_set_timeout($this->sock, $this->timeout); + + return true; + } + + public function close() + { + if (is_resource($this->sock) === true) { + + @fclose($this->sock); + } + return true; + } + + public function write($data) + { + $length = strlen($data); + if ($length == 0) { + + $this->last_error = 'empty data on write()'; + return false; + } + + $read = null; + $write = array($this->sock); + $except = null; + + // + + // + $result = stream_select($read, $write, $except, $this->timeout); + if ($result === false) { + + $this->last_error = 'failed on write select()'; + return false; + + } else if ($result == 0) { + + $this->last_error = 'timeout on write select()'; + return false; + } + + // + + // + if ($this->type == Net_DNS2_Socket::SOCK_STREAM) { + + $s = chr($length >> 8) . chr($length); + + if (@fwrite($this->sock, $s) === false) { + + $this->last_error = 'failed to fwrite() 16bit length'; + return false; + } + } + + // + + // + $size = @fwrite($this->sock, $data); + if ( ($size === false) || ($size != $length) ) { + + $this->last_error = 'failed to fwrite() packet'; + return false; + } + + return true; + } + + public function read(&$size, $max_size) + { + $read = array($this->sock); + $write = null; + $except = null; + + // + + // + @stream_set_blocking($this->sock, 0); + + // + + // + $result = stream_select($read, $write, $except, $this->timeout); + if ($result === false) { + + $this->last_error = 'error on read select()'; + return false; + + } else if ($result == 0) { + + $this->last_error = 'timeout on read select()'; + return false; + } + + $data = ''; + $length = $max_size; + + // + + // + if ($this->type == Net_DNS2_Socket::SOCK_STREAM) { + + if (($data = fread($this->sock, 2)) === false) { + + $this->last_error = 'failed on fread() for data length'; + return false; + } + + $length = ord($data[0]) << 8 | ord($data[1]); + if ($length < Net_DNS2_Lookups::DNS_HEADER_SIZE) { + + return false; + } + } + + // + + // + + // + @stream_set_blocking($this->sock, 1); + + // + + // + $data = ''; + + // + + // + + // + if ($this->type == Net_DNS2_Socket::SOCK_STREAM) { + + $chunk = ''; + $chunk_size = $length; + + // + + // + while (1) { + + $chunk = fread($this->sock, $chunk_size); + if ($chunk === false) { + + $this->last_error = 'failed on fread() for data'; + return false; + } + + $data .= $chunk; + $chunk_size -= strlen($chunk); + + if (strlen($data) >= $length) { + break; + } + } + + } else { + + // + + // + $data = fread($this->sock, $length); + if ($length === false) { + + $this->last_error = 'failed on fread() for data'; + return false; + } + } + + $size = strlen($data); + + return $data; + } +} + +?> \ No newline at end of file diff --git a/signup/email/ipaddr.php b/signup/email/ipaddr.php new file mode 100644 index 0000000..691bbea --- /dev/null +++ b/signup/email/ipaddr.php @@ -0,0 +1,210 @@ + $segment) + { + $segment = trim($segment); + if ($segment != "") $ipaddr2[] = $segment; + else if ($foundpos === false && count($ipaddr) > $num + 1 && $ipaddr[$num + 1] != "") + { + $foundpos = count($ipaddr2); + $ipaddr2[] = "0000"; + } + } + // Convert ::ffff:123.123.123.123 format. + if (strpos($ipaddr2[count($ipaddr2) - 1], ".") !== false) + { + $x = count($ipaddr2) - 1; + if ($ipaddr2[count($ipaddr2) - 2] != "ffff") $ipaddr2[$x] = "0"; + else + { + $ipaddr = explode(".", $ipaddr2[$x]); + if (count($ipaddr) != 4) $ipaddr2[$x] = "0"; + else + { + $ipaddr2[$x] = str_pad(strtolower(dechex($ipaddr[0])), 2, "0", STR_PAD_LEFT) . str_pad(strtolower(dechex($ipaddr[1])), 2, "0", STR_PAD_LEFT); + $ipaddr2[] = str_pad(strtolower(dechex($ipaddr[2])), 2, "0", STR_PAD_LEFT) . str_pad(strtolower(dechex($ipaddr[3])), 2, "0", STR_PAD_LEFT); + } + } + } + $ipaddr = array_slice($ipaddr2, 0, 8); + if ($foundpos !== false && count($ipaddr) < 8) array_splice($ipaddr, $foundpos, 0, array_fill(0, 8 - count($ipaddr), "0000")); + foreach ($ipaddr as $num => $segment) + { + $ipaddr[$num] = substr(str_pad(strtolower(dechex(hexdec($segment))), 4, "0", STR_PAD_LEFT), -4); + } + $ipv6addr = implode(":", $ipaddr); + + // Extract IPv4 address. + if (substr($ipv6addr, 0, 30) == "0000:0000:0000:0000:0000:ffff:") $ipv4addr = hexdec(substr($ipv6addr, 30, 2)) . "." . hexdec(substr($ipv6addr, 32, 2)) . "." . hexdec(substr($ipv6addr, 35, 2)) . "." . hexdec(substr($ipv6addr, 37, 2)); + + // Make a short IPv6 address. + $shortipv6 = $ipv6addr; + $pattern = "0000:0000:0000:0000:0000:0000:0000"; + do + { + $shortipv6 = str_replace($pattern, ":", $shortipv6); + $pattern = substr($pattern, 5); + } while (strlen($shortipv6) == 39 && $pattern != ""); + $shortipv6 = explode(":", $shortipv6); + foreach ($shortipv6 as $num => $segment) + { + if ($segment != "") $shortipv6[$num] = strtolower(dechex(hexdec($segment))); + } + $shortipv6 = implode(":", $shortipv6); + + return array("ipv6" => $ipv6addr, "shortipv6" => $shortipv6, "ipv4" => $ipv4addr); + } + + static function GetRemoteIP($proxies = array()) + { + $ipaddr = self::NormalizeIP(isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : "127.0.0.1"); + + // Check for trusted proxies. Stop at first untrusted IP in the chain. + if (isset($proxies[$ipaddr["ipv6"]]) || ($ipaddr["ipv4"] != "" && isset($proxies[$ipaddr["ipv4"]]))) + { + $xforward = (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ? explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"]) : array()); + $clientip = (isset($_SERVER["HTTP_CLIENT_IP"]) ? explode(",", $_SERVER["HTTP_CLIENT_IP"]) : array()); + + do + { + $found = false; + + if (isset($proxies[$ipaddr["ipv6"]])) $header = $proxies[$ipaddr["ipv6"]]; + else $header = $proxies[$ipaddr["ipv4"]]; + + $header = strtolower($header); + if ($header == "xforward" && count($xforward) > 0) + { + $ipaddr = self::NormalizeIP(array_pop($xforward)); + $found = true; + } + else if ($header == "clientip" && count($clientip) > 0) + { + $ipaddr = self::NormalizeIP(array_pop($clientip)); + $found = true; + } + } while ($found && (isset($proxies[$ipaddr["ipv6"]]) || ($ipaddr["ipv4"] != "" && isset($proxies[$ipaddr["ipv4"]])))); + } + + return $ipaddr; + } + + static function IsMatch($pattern, $ipaddr) + { + if (is_string($ipaddr)) $ipaddr = self::NormalizeIP($ipaddr); + + if (strpos($pattern, ":") !== false) + { + // Pattern is IPv6. + $pattern = explode(":", strtolower($pattern)); + $ipaddr = explode(":", $ipaddr["ipv6"]); + if (count($pattern) != 8 || count($ipaddr) != 8) return false; + foreach ($pattern as $num => $segment) + { + $found = false; + $pieces = explode(",", $segment); + foreach ($pieces as $piece) + { + $piece = trim($piece); + $piece = explode(".", $piece); + if (count($piece) == 1) + { + $piece = $piece[0]; + + if ($piece == "*") $found = true; + else if (strpos($piece, "-") !== false) + { + $range = explode("-", $piece); + $range[0] = hexdec($range[0]); + $range[1] = hexdec($range[1]); + $val = hexdec($ipaddr[$num]); + if ($range[0] > $range[1]) $range[0] = $range[1]; + if ($val >= $range[0] && $val <= $range[1]) $found = true; + } + else if ($piece === $ipaddr[$num]) $found = true; + } + else if (count($piece) == 2) + { + // Special IPv4-like notation. + $found2 = false; + $found3 = false; + $val = hexdec(substr($ipaddr[$num], 0, 2)); + $val2 = hexdec(substr($ipaddr[$num], 2, 2)); + + if ($piece[0] == "*") $found2 = true; + else if (strpos($piece[0], "-") !== false) + { + $range = explode("-", $piece[0]); + if ($range[0] > $range[1]) $range[0] = $range[1]; + if ($val >= $range[0] && $val <= $range[1]) $found2 = true; + } + else if ($piece[0] == $val) $found2 = true; + + if ($piece[1] == "*") $found3 = true; + else if (strpos($piece[1], "-") !== false) + { + $range = explode("-", $piece[1]); + if ($range[0] > $range[1]) $range[0] = $range[1]; + if ($val >= $range[0] && $val <= $range[1]) $found3 = true; + } + else if ($piece[1] == $val2) $found3 = true; + + if ($found2 && $found3) $found = true; + } + + if ($found) break; + } + + if (!$found) return false; + } + } + else + { + // Pattern is IPv4. + $pattern = explode(".", strtolower($pattern)); + $ipaddr = explode(".", $ipaddr["ipv4"]); + if (count($pattern) != 4 || count($ipaddr) != 4) return false; + foreach ($pattern as $num => $segment) + { + $found = false; + $pieces = explode(",", $segment); + foreach ($pieces as $piece) + { + $piece = trim($piece); + + if ($piece == "*") $found = true; + else if (strpos($piece, "-") !== false) + { + $range = explode("-", $piece); + if ($range[0] > $range[1]) $range[0] = $range[1]; + if ($ipaddr[$num] >= $range[0] && $ipaddr[$num] <= $range[1]) $found = true; + } + else if ($piece == $ipaddr[$num]) $found = true; + + if ($found) break; + } + + if (!$found) return false; + } + } + + return true; + } + } +?> \ No newline at end of file diff --git a/signup/email/smtp.php b/signup/email/smtp.php new file mode 100644 index 0000000..b4cd6d3 --- /dev/null +++ b/signup/email/smtp.php @@ -0,0 +1,1519 @@ += 37 && $currchr <= 45) || ($currchr >= 47 && $currchr <= 60) || $currchr == 62 || $currchr == 63 || ($currchr >= 65 && $currchr <= 90) || $currchr == 95 || ($currchr >= 97 && $currchr <= 122)) + { + if (!$restrictmore) $data2 .= $data[$x]; + else if (($currchr >= 48 && $currchr <= 57) || ($currchr >= 65 && $currchr <= 90) || ($currchr >= 97 && $currchr <= 122)) $data2 .= sprintf("=%02X", $currchr); + else $data2 .= $data[$x]; + } + else if ($currchr == 13 && $x + 1 < $y && ord($data[$x + 1]) == 10) + { + $data2 .= "\r\n"; + $x++; + } + else + { + $data2 .= sprintf("=%02X", $currchr); + } + } + + // Break the string on 75 character boundaries and add '=' character. + $data2 = explode("\r\n", $data2); + $result = ""; + foreach ($data2 as $currline) + { + $x2 = 0; + $y2 = strlen($currline); + while ($x2 + 75 < $y2) + { + if ($currline[$x2 + 74] == '=') + { + $result .= substr($currline, $x2, 74); + $x2 += 74; + } + else if ($currline[$x2 + 73] == '=') + { + $result .= substr($currline, $x2, 73); + $x2 += 73; + } + else + { + $result .= substr($currline, $x2, 75); + $x2 += 75; + } + $result .= "=\r\n"; + } + + if ($x2 < $y2) $result .= substr($currline, $x2, $y2 - $x2); + $result .= "\r\n"; + } + + return $result; + } + + public static function ConvertEmailMessageToRFC1341($data, $restrictmore = false) + { + $data = self::ReplaceNewlines("\r\n", $data); + + return self::ConvertToRFC1341($data, $restrictmore); + } + + // RFC1342 is a hacky workaround to encode headers in e-mails. + public static function ConvertToRFC1342($data, $lang = "UTF-8", $encodeb64 = true) + { + $result = ""; + + // An individual RFC1342-compliant string can only be 75 characters long, 6 must be markers, + // one must be the encoding method, and at least one must be data (adjusted to 4 required + // spaces to simplify processing). + if (strlen($lang) > 75 - 6 - 1 - 4) return $result; + + $lang = strtoupper($lang); + if ($lang != "ISO-8859-1" && $lang != "US-ASCII") $encodeb64 = true; + + $maxdatalength = 75 - 6 - strlen($lang) - 1; + if ($encodeb64) + { + $maxdatalength = $maxdatalength * 3 / 4; + $y = strlen($data); + if ($lang == "UTF-8") + { + $x = 0; + $pos = 0; + $size = 0; + while (UTF8::NextChrPos($data, $y, $pos, $size)) + { + if ($pos + $size - $x > $maxdatalength) + { + if ($x) $result .= " "; + $result .= "=?" . $lang . "?B?" . base64_encode(substr($data, $x, $pos - $x)) . "?="; + $x = $pos; + } + } + } + else + { + for ($x = 0; $x + $maxdatalength < $y; $x += $maxdatalength) + { + if ($x) $result .= " "; + $result .= "=?" . $lang . "?B?" . base64_encode(substr($data, $x, $maxdatalength)) . "?="; + } + } + + if ($x < $y) + { + if ($x) $result .= " "; + $result .= "=?" . $lang . "?B?" . base64_encode(substr($data, $x, $y - $x)) . "?="; + } + } + else + { + // Quoted printable. + $maxdatalength = $maxdatalength / 3; + $y = strlen($data); + for ($x = 0; $x + $maxdatalength < $y; $x += $maxdatalength) + { + if ($x) $result .= " "; + $result .= "=?" . $lang . "?Q?" . str_replace(" ", "_", self::ConvertToRFC1341(substr($data, $x, $maxdatalength), true)) . "?="; + } + if ($x < $y) + { + if ($x) $result .= " "; + $result .= "=?" . $lang . "?Q?" . str_replace(" ", "_", self::ConvertToRFC1341(substr($data, $x, $y - $x), true)) . "?="; + } + } + + return $result; + } + + private static function SMTP_Translate() + { + $args = func_get_args(); + if (!count($args)) return ""; + + return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); + } + + // Takes a potentially invalid e-mail address and attempts to make it valid. + public static function MakeValidEmailAddress($email, $options = array()) + { + $email = str_replace("\t", " ", $email); + $email = str_replace("\r", " ", $email); + $email = str_replace("\n", " ", $email); + $email = trim($email); + + // Reverse parse out the initial domain/IP address part of the e-mail address. + $domain = ""; + $state = "domend"; + $cfwsdepth = 0; + while ($email != "" && $state != "") + { + $prevchr = substr($email, -2, 1); + $lastchr = substr($email, -1); + + switch ($state) + { + case "domend": + { + if ($lastchr == ")") + { + $laststate = "domain"; + $state = "cfws"; + } + else if ($lastchr == "]" || $lastchr == "}") + { + $domain .= "]"; + $email = trim(substr($email, 0, -1)); + $state = "ipaddr"; + } + else + { + $state = "domain"; + } + + break; + } + case "cfws": + { + if ($prevchr == "\\") $email = trim(substr($email, 0, -2)); + else if ($lastchr == ")") + { + $email = trim(substr($email, 0, -1)); + $depth++; + } + else if ($lastchr == "(") + { + $email = trim(substr($email, 0, -1)); + $depth--; + if (!$depth && substr($email, -1) != ")") $state = $laststate; + } + else $email = trim(substr($email, 0, -1)); + + break; + } + case "ipaddr": + { + if ($lastchr == "[" || $lastchr == "{" || $lastchr == "@") + { + $domain .= "["; + $state = "@"; + + if ($lastchr == "@") break; + } + else if ($lastchr == "," || $lastchr == ".") $domain .= "."; + else if ($lastchr == ";" || $lastchr == ":") $domain .= ":"; + else if (preg_match('/[A-Za-z0-9]/', $lastchr)) $domain .= $lastchr; + + $email = trim(substr($email, 0, -1)); + + break; + } + case "domain": + { + if ($lastchr == "@") + { + $state = "@"; + + break; + } + else if ($lastchr == ")") + { + $state = "cfws"; + $laststate = "@"; + + break; + } + else if ($lastchr == "," || $lastchr == ".") $domain .= "."; + else if (preg_match('/[A-Za-z0-9-]/', $lastchr)) $domain .= $lastchr; + + $email = trim(substr($email, 0, -1)); + + break; + } + case "@": + { + if ($lastchr == "@") $state = ""; + + $email = trim(substr($email, 0, -1)); + + break; + } + } + } + $domain = strrev($domain); + $parts = explode(".", $domain); + foreach ($parts as $num => $part) $parts[$num] = str_replace(" ", "-", trim(str_replace("-", " ", $part))); + $domain = implode(".", $parts); + + // Forward parse out the local part of the e-mail address. + // Remove CFWS (comments, folding whitespace). + while (substr($email, 0, 1) == "(") + { + while ($email != "") + { + $currchr = substr($email, 0, 1); + if ($currchr == "\\") $email = trim(substr($email, 2)); + else if ($currchr == "(") + { + $depth++; + $email = trim(substr($email, 1)); + } + else if ($currchr == ")") + { + $email = trim(substr($email, 1)); + $depth--; + if (!$depth && substr($email, 0, 1) != "(") break; + } + } + } + + // Process quoted/unquoted string. + $local = ""; + if (substr($email, 0, 1) == "\"") + { + $email = substr($email, 1); + while ($email != "") + { + $currchr = substr($email, 0, 1); + $nextchr = substr($email, 1, 1); + + if ($currchr == "\\") + { + if ($nextchr == "\\" || $nextchr == "\"") + { + $local .= substr($email, 0, 2); + $email = substr($email, 2); + } + else if (ord($nextchr) >= 33 && ord($nextchr) <= 126) + { + $local .= substr($email, 1, 1); + $email = substr($email, 2); + } + } + else if ($currchr == "\"") break; + else if (ord($currchr) >= 33 && ord($nextchr) <= 126) + { + $local .= substr($email, 0, 1); + $email = substr($email, 1); + } + else $email = substr($email, 1); + } + + if (substr($local, -1) != "\"") $local .= "\""; + } + else + { + while ($email != "") + { + $currchr = substr($email, 0, 1); + + if (preg_match("/[A-Za-z0-9]/", $currchr) || $currchr == "!" || $currchr == "#" || $currchr == "\$" || $currchr == "%" || $currchr == "&" || $currchr == "'" || $currchr == "*" || $currchr == "+" || $currchr == "-" || $currchr == "/" || $currchr == "=" || $currchr == "?" || $currchr == "^" || $currchr == "_" || $currchr == "`" || $currchr == "{" || $currchr == "|" || $currchr == "}" || $currchr == "~" || $currchr == ".") + { + $local .= $currchr; + $email = substr($email, 1); + } + else break; + } + + $local = preg_replace('/[.]+/', ".", $local); + if (substr($local, 0, 1) == ".") $local = substr($local, 1); + if (substr($local, -1) == ".") $local = substr($local, 0, -1); + } + while (substr($local, -2) == "\\\"") $local = substr($local, 0, -2) . "\""; + if ($local == "\"" || $local == "\"\"") $local = ""; + + // Analyze the domain/IP part and fix any issues. + $domain = preg_replace('/[.]+/', ".", $domain); + if (substr($domain, -1) == "]") + { + if (substr($domain, 0, 1) != "[") $domain = "[" . $domain; + + // Process the IP address. + if (strtolower(substr($domain, 0, 6)) == "[ipv6:") $ipaddr = IPAddr::NormalizeIP(substr($domain, 6, -1)); + else $ipaddr = IPAddr::NormalizeIP(substr($domain, 1, -1)); + + if ($ipaddr["ipv4"] != "") $domain = "[" . $ipaddr["ipv4"] . "]"; + else $domain = "[IPv6:" . $ipaddr["ipv6"] . "]"; + } + else + { + // Process the domain. + if (substr($domain, 0, 1) == ".") $domain = substr($domain, 1); + if (substr($domain, -1) == ".") $domain = substr($domain, 0, -1); + $domain = explode(".", $domain); + foreach ($domain as $num => $part) + { + if (substr($part, 0, 1) == "-") $part = substr($part, 1); + if (substr($part, -1) == "-") $part = substr($part, 0, -1); + if (strlen($part) > 63) $part = substr($part, 0, 63); + + $domain[$num] = $part; + } + + $domain = implode(".", $domain); + } + + // Validate the final lengths. + $y = strlen($local); + $y2 = strlen($domain); + $email = $local . "@" . $domain; + if (!$y) return array("success" => false, "error" => self::SMTP_Translate("Missing local part of e-mail address."), "errorcode" => "missing_local_part", "info" => $email); + if (!$y2) return array("success" => false, "error" => self::SMTP_Translate("Missing domain part of e-mail address."), "errorcode" => "missing_domain_part", "info" => $email); + if ($y > 64 || $y2 > 253 || $y + $y2 + 1 > 253) return array("success" => false, "error" => self::SMTP_Translate("E-mail address is too long."), "errorcode" => "email_too_long", "info" => $email); + + // Process results. + if (substr($domain, 0, 1) == "[" && substr($domain, -1) == "]") $result = array("success" => true, "email" => $email, "lookup" => false, "type" => "IP"); + else if (isset($options["usedns"]) && $options["usedns"] === false) $result = array("success" => true, "email" => $email, "lookup" => false, "type" => "Domain"); + else if ((!isset($options["usednsttlcache"]) || $options["usednsttlcache"] === true) && isset(self::$dnsttlcache[$domain]) && self::$dnsttlcache[$domain] >= time()) $result = array("success" => true, "email" => $email, "lookup" => false, "type" => "CachedDNS"); + else + { + // Check for a mail server based on a DNS lookup. + $result = self::GetDNSRecord($domain, array("MX", "A"), (isset($options["nameservers"]) ? $options["nameservers"] : array("8.8.8.8", "8.8.4.4")), (!isset($options["usednsttlcache"]) || $options["usednsttlcache"] === true)); + if ($result["success"]) $result = array("success" => true, "email" => $email, "lookup" => true, "type" => $result["type"], "records" => $result["records"]); + } + + return $result; + } + + public static function UpdateDNSTTLCache() + { + $ts = time(); + foreach (self::$dnsttlcache as $domain => $ts2) + { + if ($ts2 > $ts) unset(self::$dnsttlcache[$domain]); + } + } + + public static function GetDNSRecord($domain, $types = array("MX", "A"), $nameservers = array("8.8.8.8", "8.8.4.4"), $cache = true) + { + // Check for a mail server based on a DNS lookup. + if (!class_exists("Net_DNS2_Resolver")) require_once str_replace("\\", "/", dirname(__FILE__)) . "/Net/DNS2.php"; + + $resolver = new Net_DNS2_Resolver(array("nameservers" => $nameservers)); + try + { + foreach ($types as $type) + { + $response = $resolver->query($domain, $type); + if ($response && count($response->answer)) + { + if ($cache) + { + $minttl = -1; + foreach ($response->answer as $answer) + { + if ($minttl < 0 || ($answer->ttl > 0 && $answer->ttl < $minttl)) $minttl = $answer->ttl; + } + + self::$dnsttlcache[$domain] = time() + $minttl; + } + + return array("success" => true, "type" => $type, "records" => $response); + } + } + + return array("success" => false, "error" => self::SMTP_Translate("Invalid domain name or missing DNS record."), "errorcode" => "invalid_domain_or_missing_record", "info" => $domain); + } + catch (Exception $e) + { + return array("success" => false, "error" => self::SMTP_Translate("Invalid domain name. Internal exception occurred."), "errorcode" => "dns_library_exception", "info" => self::SMTP_Translate("%s (%s).", $e->getMessage(), $domain)); + } + } + + public static function EmailAddressesToNamesAndEmail(&$destnames, &$destaddrs, $emailaddrs, $removenames = false, $options = array()) + { + $destnames = array(); + $destaddrs = array(); + + $data = str_replace("\t", " ", $emailaddrs); + $data = str_replace("\r", " ", $data); + $data = str_replace("\n", " ", $data); + $data = trim($data); + + // Parse e-mail addresses out of the string with a state engine. + // Parsed in reverse because that is easier than trying to figure out if each address + // starts with a name OR a quoted string for the local part of the e-mail address. + // The e-mail address parsing in this state engine is intentionally incomplete. + // The goal is to identify '"name" , name , emailaddr' variations. + $found = false; + while ($data != "") + { + $name = ""; + $email = ""; + $state = "addrend"; + $cfwsdepth = 0; + $inbracket = false; + + while ($data != "" && $state != "") + { + $prevchr = substr($data, -2, 1); + $lastchr = substr($data, -1); + + switch ($state) + { + case "addrend": + { + if ($lastchr == ">") + { + $data = trim(substr($data, 0, -1)); + $inbracket = true; + $state = "domend"; + } + else if ($lastchr == "," || $lastchr == ";") + { + $data = trim(substr($data, 0, -1)); + } + else $state = "domend"; + + break; + } + case "domend": + { + if ($lastchr == ")") + { + $laststate = "domain"; + $state = "cfws"; + } + else if ($lastchr == "]" || $lastchr == "}") + { + $email .= "]"; + $data = trim(substr($data, 0, -1)); + $state = "ipaddr"; + } + else + { + $state = "domain"; + } + + break; + } + case "cfws": + { + if ($prevchr == "\\") $data = trim(substr($data, 0, -2)); + else if ($lastchr == ")") + { + $data = trim(substr($data, 0, -1)); + $depth++; + } + else if ($lastchr == "(") + { + $data = trim(substr($data, 0, -1)); + $depth--; + if (!$depth && substr($data, -1) != ")") $state = $laststate; + } + else $data = trim(substr($data, 0, -1)); + + break; + } + case "ipaddr": + { + if ($lastchr == "[" || $lastchr == "{" || $lastchr == "@") + { + $email .= "["; + $state = "@"; + + if ($lastchr == "@") break; + } + else if ($lastchr == "," || $lastchr == ".") $email .= "."; + else if ($lastchr == ";" || $lastchr == ":") $email .= ":"; + else if (preg_match('/[A-Za-z0-9]/', $lastchr)) $email .= $lastchr; + + $data = trim(substr($data, 0, -1)); + + break; + } + case "domain": + { + if ($lastchr == "@") + { + $state = "@"; + + break; + } + else if ($lastchr == ")") + { + $state = "cfws"; + $laststate = "@"; + + break; + } + else if ($lastchr == "," || $lastchr == ".") $email .= "."; + else if (preg_match('/[A-Za-z0-9-]/', $lastchr)) $email .= $lastchr; + + $data = trim(substr($data, 0, -1)); + + break; + } + case "@": + { + if ($lastchr == "@") + { + $email .= "@"; + $state = "localend"; + } + + $data = trim(substr($data, 0, -1)); + + break; + } + case "localend": + { + if ($lastchr == ")") + { + $state = "cfws"; + $laststate = "localend"; + } + else if ($lastchr == "\"") + { + $email .= "\""; + $data = substr($data, 0, -1); + $state = "quotedlocal"; + } + else $state = "local"; + + break; + } + case "quotedlocal": + { + if ($prevchr == "\\") + { + $email .= $lastchar . $prevchr; + $data = substr($data, 0, -2); + } + else if ($lastchr == "\"") + { + $email .= $lastchar; + $data = trim(substr($data, 0, -1)); + $state = "localstart"; + } + else + { + $email .= $lastchar; + $data = substr($data, 0, -1); + } + + break; + } + case "local": + { + if (preg_match("/[A-Za-z0-9]/", $lastchr) || $lastchr == "!" || $lastchr == "#" || $lastchr == "\$" || $lastchr == "%" || $lastchr == "&" || $lastchr == "'" || $lastchr == "*" || $lastchr == "+" || $lastchr == "-" || $lastchr == "/" || $lastchr == "=" || $lastchr == "?" || $lastchr == "^" || $lastchr == "_" || $lastchr == "`" || $lastchr == "{" || $lastchr == "|" || $lastchr == "}" || $lastchr == "~" || $lastchr == ".") + { + $email .= $lastchr; + $data = substr($data, 0, -1); + } + else if ($lastchr == ")") + { + $state = "cfws"; + $laststate = "localstart"; + } + else if ($inbracket) + { + if ($lastchr == "<") $state = "localstart"; + else $data = substr($data, 0, -1); + } + else if ($lastchr == " " || $lastchr == "," || $lastchr == ";") $state = "localstart"; + else $data = substr($data, 0, -1); + + break; + } + case "localstart": + { + if ($inbracket) + { + if ($lastchr == "<") $state = "nameend"; + + $data = trim(substr($data, 0, -1)); + } + else if ($lastchr == "," || $lastchr == ";") $state = ""; + else $data = trim(substr($data, 0, -1)); + + break; + } + case "nameend": + { + if ($lastchr == "\"") + { + $data = substr($data, 0, -1); + $state = "quotedname"; + } + else $state = "name"; + + break; + } + case "quotedname": + { + if ($prevchr == "\\") + { + $name .= $lastchar . $prevchr; + $data = substr($data, 0, -2); + } + else if ($lastchr == "\"") + { + $data = trim(substr($data, 0, -1)); + $state = ""; + } + else + { + $name .= $lastchr; + $data = substr($data, 0, -1); + } + + break; + } + case "name": + { + if ($lastchr == "," || $lastchr == ";") $state = ""; + else + { + $name .= $lastchr; + $data = substr($data, 0, -1); + } + + break; + } + } + } + + $email = self::MakeValidEmailAddress(strrev($email), $options); + if ($email["success"]) + { + if ($removenames) $name = ""; + $name = trim(strrev($name)); + if (substr($name, 0, 1) == "\"") $name = trim(substr($name, 1)); + $name = str_replace("\\\\", "\\", $name); + $name = str_replace("\\\"", "\"", $name); + + $destnames[] = $name; + $destaddrs[] = $email["email"]; + + $found = true; + } + + $data = trim($data); + } + + $destnames = array_reverse($destnames); + $destaddrs = array_reverse($destaddrs); + + return $found; + } + + // Takes in a comma-separated list of e-mail addresses and returns appropriate e-mail headers. + public static function EmailAddressesToEmailHeaders($emailaddrs, $headername, $multiple = true, $removenames = false, $options = array()) + { + $result = ""; + + $tempnames = array(); + $tempaddrs = array(); + self::EmailAddressesToNamesAndEmail($tempnames, $tempaddrs, $emailaddrs, $removenames, $options); + + $y = count($tempnames); + for ($x = 0; $x < $y && ($multiple || $result == ""); $x++) + { + $name = $tempnames[$x]; + $emailaddr = $tempaddrs[$x]; + + if ($name != "" && !UTF8::IsASCII($name)) $name = self::ConvertToRFC1342($name) . " "; + else if ($name != "") $name = '"' . $name . '" '; + if ($result != "") $result .= ",\r\n "; + if ($name != "") $result .= $name . '<' . $emailaddr . '>'; + else $result .= $emailaddr; + } + + if ($result != "" && $headername != "") $result = $headername . ": " . $result . "\r\n"; + + return $result; + } + + public static function GetUserAgent($type) + { + if ($type == "Thunderbird") return "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.0\r\n"; + else if ($type == "Thunderbird2") return "X-Mailer: Thunderbird 2.0.0.16 (Windows/20080708)\r\n"; + else if ($type == "OutlookExpress") return "X-Mailer: Microsoft Outlook Express 6.00.2900.3198\r\nX-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3198\r\n"; + else if ($type == "Exchange") return "X-Mailer: Produced By Microsoft Exchange V6.0.6619.12\r\n"; + else if ($type == "OfficeOutlook") return "X-Mailer: Microsoft Office Outlook 12.0\r\n"; + + return ""; + } + + public static function GetTimeLeft($start, $limit) + { + if ($limit === false) return false; + + $difftime = microtime(true) - $start; + if ($difftime >= $limit) return 0; + + return $limit - $difftime; + } + + private static function ProcessRateLimit($size, $start, $limit, $async) + { + $difftime = microtime(true) - $start; + if ($difftime > 0.0) + { + if ($size / $difftime > $limit) + { + // Sleeping for some amount of time will equalize the rate. + // So, solve this for $x: $size / ($x + $difftime) = $limit + $amount = ($size - ($limit * $difftime)) / $limit; + + if ($async) return microtime(true) + $amount; + else usleep($amount); + } + } + + return -1.0; + } + + private static function StreamTimedOut($fp) + { + if (!function_exists("stream_get_meta_data")) return false; + + $info = stream_get_meta_data($fp); + + return $info["timed_out"]; + } + + // Reads one or more lines in. + private static function ProcessState__ReadLine(&$state) + { + while (strpos($state["data"], "\n") === false) + { + $data2 = @fgets($state["fp"], 116000); + if ($data2 === false) return array("success" => false, "error" => self::SMTP_Translate("Underlying stream encountered a read error."), "errorcode" => "stream_read_error"); + if (strpos($data2, "\n") === false) + { + if (feof($state["fp"])) return array("success" => false, "error" => self::SMTP_Translate("Remote peer disconnected."), "errorcode" => "peer_disconnected"); + if (self::StreamTimedOut($state["fp"])) return array("success" => false, "error" => self::SMTP_Translate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); + + if ($state["async"] && $data2 === "") return array("success" => false, "error" => self::SMTP_Translate("Non-blocking read returned no data."), "errorcode" => "no_data"); + } + if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return array("success" => false, "error" => self::SMTP_Translate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); + + $state["result"]["rawrecvsize"] += strlen($data2); + $state["data"] .= $data2; + + if (isset($state["options"]["recvratelimit"])) $state["waituntil"] = self::ProcessRateLimit($state["rawsize"], $state["recvstart"], $state["options"]["recvratelimit"], $state["async"]); + + if (isset($state["options"]["debug_callback"]) && is_callable($state["options"]["debug_callback"])) call_user_func_array($state["options"]["debug_callback"], array("rawrecv", $data2, &$state["options"]["debug_callback_opts"])); + else if ($state["debug"]) $state["result"]["rawrecv"] .= $data2; + } + + return array("success" => true); + } + + // Writes data out. + private static function ProcessState__WriteData(&$state) + { + if ($state["data"] !== "") + { + $result = @fwrite($state["fp"], $state["data"]); + if ($result === false || feof($state["fp"])) return array("success" => false, "error" => self::SMTP_Translate("A fwrite() failure occurred. Most likely cause: Connection failure."), "errorcode" => "fwrite_failed"); + if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return array("success" => false, "error" => self::SMTP_Translate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); + + $data2 = substr($state["data"], 0, $result); + $state["data"] = (string)substr($state["data"], $result); + + $state["result"]["rawsendsize"] += $result; + + if (isset($state["options"]["sendratelimit"])) + { + $state["waituntil"] = self::ProcessRateLimit($state["result"]["rawsendsize"], $state["result"]["connected"], $state["options"]["sendratelimit"], $state["async"]); + if (microtime(true) < $state["waituntil"]) return array("success" => false, "error" => self::SMTP_Translate("Rate limit for non-blocking connection has not been reached."), "errorcode" => "no_data"); + } + + if (isset($state["options"]["debug_callback"]) && is_callable($state["options"]["debug_callback"])) call_user_func_array($state["options"]["debug_callback"], array("rawsend", $data2, &$state["options"]["debug_callback_opts"])); + else if ($state["debug"]) $state["result"]["rawsend"] .= $data2; + } + + return array("success" => true); + } + + public static function ForceClose(&$state) + { + if ($state["fp"] !== false) + { + @fclose($state["fp"]); + $state["fp"] = false; + } + + if (isset($state["currentfile"]) && $state["currentfile"] !== false) + { + if ($state["currentfile"]["fp"] !== false) @fclose($state["currentfile"]["fp"]); + $state["currentfile"] = false; + } + } + + private static function CleanupErrorState(&$state, $result) + { + if (!$result["success"] && $result["errorcode"] !== "no_data") + { + self::ForceClose($state); + + $state["error"] = $result; + } + + return $result; + } + + private static function InitSMTPRequest(&$state, $command, $expectedcode, $nextstate, $expectederror) + { + $state["data"] = $command . "\r\n"; + $state["state"] = "send_request"; + $state["expectedcode"] = $expectedcode; + $state["nextstate"] = $nextstate; + $state["expectederror"] = $expectederror; + } + + public static function ProcessState(&$state) + { + if (isset($state["error"])) return $state["error"]; + + if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return self::CleanupErrorState($state, array("success" => false, "error" => self::SMTP_Translate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded")); + if (microtime(true) < $state["waituntil"]) return array("success" => false, "error" => self::SMTP_Translate("Rate limit for non-blocking connection has not been reached."), "errorcode" => "no_data"); + + while ($state["state"] !== "done") + { + switch ($state["state"]) + { + case "connecting": + { + if (function_exists("stream_select") && $state["async"]) + { + $readfp = NULL; + $writefp = array($state["fp"]); + $exceptfp = NULL; + $result = @stream_select($readfp, $writefp, $exceptfp, 0); + if ($result === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::SMTP_Translate("A stream_select() failure occurred. Most likely cause: Connection failure."), "errorcode" => "stream_select_failed")); + + if (!count($writefp)) return array("success" => false, "error" => self::SMTP_Translate("Connection not established yet."), "errorcode" => "no_data"); + } + + // Handle peer certificate retrieval. + if (function_exists("stream_context_get_options")) + { + $contextopts = stream_context_get_options($state["fp"]); + if ($state["secure"] && isset($state["options"]["sslopts"]) && is_array($state["options"]["sslopts"]) && isset($contextopts["ssl"]["peer_certificate"])) + { + if (isset($state["options"]["debug_callback"]) && is_callable($state["options"]["debug_callback"])) call_user_func_array($state["options"]["debug_callback"], array("peercert", @openssl_x509_parse($contextopts["ssl"]["peer_certificate"]), &$state["options"]["debug_callback_opts"])); + } + } + + // Deal with failed connections that hang applications. + if (isset($state["options"]["streamtimeout"]) && $state["options"]["streamtimeout"] !== false && function_exists("stream_set_timeout")) @stream_set_timeout($state["fp"], $state["options"]["streamtimeout"]); + + $state["result"]["connected"] = microtime(true); + + $state["data"] = ""; + $state["code"] = 0; + $state["expectedcode"] = 220; + $state["expectederror"] = self::SMTP_Translate("Expected a 220 response from the SMTP server upon connecting."); + $state["response"] = ""; + $state["state"] = "get_response"; + $state["nextstate"] = "helo_ehlo"; + + break; + } + case "send_request": + { + // Send the request to the server. + $result = self::ProcessState__WriteData($state); + if (!$result["success"]) return self::CleanupErrorState($state, $result); + + $state["code"] = 0; + $state["response"] = ""; + + // Handle QUIT differently. + $state["state"] = ($state["nextstate"] === "done" ? "done" : "get_response"); + + break; + } + case "get_response": + { + $result = self::ProcessState__ReadLine($state); + if (!$result["success"]) return self::CleanupErrorState($state, $result); + + $currline = $state["data"]; + $state["data"] = ""; + if (strlen($currline) >= 4) + { + $state["response"] .= substr($currline, 4); + $state["code"] = (int)substr($currline, 0, 3); + if (substr($currline, 3, 1) == " ") + { + if ($state["expectedcode"] > 0 && $state["code"] !== $state["expectedcode"]) return self::CleanupErrorState($state, array("success" => false, "error" => $state["expectederror"], "errorcode" => "invalid_response", "info" => $state["code"] . " " . $state["response"])); + + $state["response"] = self::ReplaceNewlines("\r\n", $state["response"]); + + $state["state"] = $state["nextstate"]; + } + } + + break; + } + case "helo_ehlo": + { + // Send EHLO or HELO depending on server support. + $hostname = (isset($state["options"]["hostname"]) ? $state["options"]["hostname"] : "[" . trim(isset($_SERVER["SERVER_ADDR"]) && $_SERVER["SERVER_ADDR"] != "127.0.0.1" ? $_SERVER["SERVER_ADDR"] : "192.168.0.101") . "]"); + $state["size_supported"] = 0; + if (strpos($state["response"], " ESMTP") !== false) + { + self::InitSMTPRequest($state, "EHLO " . $hostname, 250, "esmtp_extensions", self::SMTP_Translate("Expected a 250 response from the SMTP server upon EHLO.")); + } + else + { + self::InitSMTPRequest($state, "HELO " . $hostname, 250, "mail_from", self::SMTP_Translate("Expected a 250 response from the SMTP server upon HELO.")); + } + + break; + } + case "esmtp_extensions": + { + // Process supported ESMTP extensions. + $auth = ""; + $smtpdata = explode("\r\n", $state["response"]); + $y = count($smtpdata); + for ($x = 1; $x < $y; $x++) + { + if (strtoupper(substr($smtpdata[$x], 0, 4)) == "AUTH" && ($smtpdata[$x][4] == ' ' || $smtpdata[$x][4] == '=')) $auth = strtoupper(substr($smtpdata[$x], 5)); + if (strtoupper(substr($smtpdata[$x], 0, 4)) == "SIZE" && ($smtpdata[$x][4] == ' ' || $smtpdata[$x][4] == '=')) $state["size_supported"] = (int)substr($smtpdata[$x], 5); + } + + $state["state"] = "mail_from"; + + // Process login (if any and supported). + if (strpos($auth, "LOGIN") !== false) + { + $state["username"] = (isset($state["options"]["username"]) ? (string)$state["options"]["username"] : ""); + $state["password"] = (isset($state["options"]["password"]) ? (string)$state["options"]["password"] : ""); + if ($state["username"] !== "" || $state["password"] !== "") + { + self::InitSMTPRequest($state, "AUTH LOGIN", 334, "auth_login_username", self::SMTP_Translate("Expected a 334 response from the SMTP server upon AUTH LOGIN.")); + } + } + + break; + } + case "auth_login_username": + { + self::InitSMTPRequest($state, base64_encode($state["username"]), 334, "auth_login_password", self::SMTP_Translate("Expected a 334 response from the SMTP server upon AUTH LOGIN username.")); + + break; + } + case "auth_login_password": + { + self::InitSMTPRequest($state, base64_encode($state["password"]), 235, "mail_from", self::SMTP_Translate("Expected a 235 response from the SMTP server upon AUTH LOGIN password.")); + + break; + } + case "mail_from": + { + self::InitSMTPRequest($state, "MAIL FROM:<" . $state["fromaddrs"][0] . ">" . ($state["size_supported"] ? " SIZE=" . strlen($state["message"]) : ""), 250, "rcpt_to", self::SMTP_Translate("Expected a 250 response from the SMTP server upon MAIL FROM.")); + + break; + } + case "rcpt_to": + { + $addr = array_shift($state["toaddrs"]); + self::InitSMTPRequest($state, "RCPT TO:<" . $addr . ">", 250, (count($state["toaddrs"]) ? "rcpt_to" : "data"), self::SMTP_Translate("Expected a 250 response from the SMTP server upon RCPT TO.")); + + break; + } + case "data": + { + self::InitSMTPRequest($state, "DATA", 354, "send_message", self::SMTP_Translate("Expected a 354 response from the SMTP server upon DATA.")); + + break; + } + case "send_message": + { + self::InitSMTPRequest($state, $state["message"] . "\r\n.", 250, "quit", self::SMTP_Translate("Expected a 250 response from the SMTP server upon sending the e-mail.")); + + break; + } + case "quit": + { + self::InitSMTPRequest($state, "QUIT", 0, "done", ""); + + break; + } + } + } + + $state["result"]["endts"] = microtime(true); + + fclose($state["fp"]); + + return $state["result"]; + } + + private static function SMTP_RandomHexString($length) + { + $lookup = "0123456789ABCDEF"; + $result = ""; + + while ($length) + { + $result .= $lookup[mt_rand(0, 15)]; + + $length--; + } + + return $result; + } + + private static function ProcessSSLOptions(&$options, $key, $host) + { + if (isset($options[$key]["auto_cainfo"])) + { + unset($options[$key]["auto_cainfo"]); + + $cainfo = ini_get("curl.cainfo"); + if ($cainfo !== false && strlen($cainfo) > 0) $options[$key]["cafile"] = $cainfo; + else if (file_exists(str_replace("\\", "/", dirname(__FILE__)) . "/cacert.pem")) $options[$key]["cafile"] = str_replace("\\", "/", dirname(__FILE__)) . "/cacert.pem"; + } + + if (isset($options[$key]["auto_cn_match"])) + { + unset($options[$key]["auto_cn_match"]); + + $options[$key]["CN_match"] = $host; + } + + if (isset($options[$key]["auto_sni"])) + { + unset($options[$key]["auto_sni"]); + + $options[$key]["SNI_enabled"] = true; + $options[$key]["SNI_server_name"] = $host; + } + } + + // Sends an e-mail by directly connecting to a SMTP server using PHP sockets. Much more powerful than calling mail(). + public static function SendSMTPEmail($toaddr, $fromaddr, $message, $options = array()) + { + $startts = microtime(true); + $timeout = (isset($options["timeout"]) ? $options["timeout"] : false); + + if (!function_exists("stream_socket_client") && !function_exists("fsockopen")) return array("success" => false, "error" => self::SMTP_Translate("The functions 'stream_socket_client' and 'fsockopen' do not exist."), "errorcode" => "function_check"); + + $temptonames = array(); + $temptoaddrs = array(); + $tempfromnames = array(); + $tempfromaddrs = array(); + if (!self::EmailAddressesToNamesAndEmail($temptonames, $temptoaddrs, $toaddr, true, $options)) return array("success" => false, "error" => self::SMTP_Translate("Invalid 'To' e-mail address(es)."), "errorcode" => "invalid_to_address", "info" => $toaddr); + if (!self::EmailAddressesToNamesAndEmail($tempfromnames, $tempfromaddrs, $fromaddr, true, $options)) return array("success" => false, "error" => self::SMTP_Translate("Invalid 'From' e-mail address."), "errorcode" => "invalid_from_address", "info" => $fromaddr); + + $server = (isset($options["server"]) ? $options["server"] : "localhost"); + $secure = (isset($options["secure"]) ? $options["secure"] : false); + $port = (isset($options["port"]) ? (int)$options["port"] : -1); + if ($port < 0 || $port > 65535) $port = ($secure ? 465 : 25); + $debug = (isset($options["debug"]) ? $options["debug"] : false); + + $headers = "Message-ID: <" . self::SMTP_RandomHexString(8) . "." . self::SMTP_RandomHexString(7) . "@" . substr($tempfromaddrs[0], strrpos($tempfromaddrs[0], "@") + 1) . ">\r\n"; + $headers .= "Date: " . date("D, d M Y H:i:s O") . "\r\n"; + + $message = $headers . $message; + $message = self::ReplaceNewlines("\r\n", $message); + $message = str_replace("\r\n.\r\n", "\r\n..\r\n", $message); + + // Set up the final output array. + $result = array("success" => true, "rawsendsize" => 0, "rawrecvsize" => 0, "startts" => $startts); + $debug = (isset($options["debug"]) && $options["debug"]); + if ($debug) + { + $result["rawsend"] = ""; + $result["rawrecv"] = ""; + } + + if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) return array("success" => false, "error" => self::SMTP_Translate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); + + // Connect to the target server. + $hostname = (isset($options["hostname"]) ? $options["hostname"] : "[" . trim(isset($_SERVER["SERVER_ADDR"]) && $_SERVER["SERVER_ADDR"] != "127.0.0.1" ? $_SERVER["SERVER_ADDR"] : "192.168.0.101") . "]"); + $errornum = 0; + $errorstr = ""; + if (isset($options["fp"]) && is_resource($options["fp"])) + { + $fp = $options["fp"]; + unset($options["fp"]); + } + else + { + if (!isset($options["connecttimeout"])) $options["connecttimeout"] = 10; + $timeleft = self::GetTimeLeft($startts, $timeout); + if ($timeleft !== false) $options["connecttimeout"] = min($options["connecttimeout"], $timeleft); + if (!function_exists("stream_socket_client")) $fp = @fsockopen(($secure ? "tls://" : "") . $server, $port, $errornum, $errorstr, $options["connecttimeout"]); + else + { + $context = @stream_context_create(); + if (isset($options["source_ip"])) $context["socket"] = array("bindto" => $options["source_ip"] . ":0"); + if ($secure && isset($options["sslopts"]) && is_array($options["sslopts"])) + { + self::ProcessSSLOptions($options, "sslopts", $server); + foreach ($options["sslopts"] as $key => $val) @stream_context_set_option($context, "ssl", $key, $val); + } + $fp = @stream_socket_client(($secure ? "tls://" : "") . $server . ":" . $port, $errornum, $errorstr, $options["connecttimeout"], STREAM_CLIENT_CONNECT | (isset($options["async"]) && $options["async"] ? STREAM_CLIENT_ASYNC_CONNECT : 0), $context); + } + + if ($fp === false) return array("success" => false, "error" => self::SMTP_Translate("Unable to establish a SMTP connection to '%s'.", ($secure ? "tls://" : "") . $server . ":" . $port), "errorcode" => "connection_failure", "info" => $errorstr . " (" . $errornum . ")"); + } + + if (function_exists("stream_set_blocking")) @stream_set_blocking($fp, (isset($options["async"]) && $options["async"] ? 0 : 1)); + + // Initialize the connection request state array. + $state = array( + "fp" => $fp, + "async" => (isset($options["async"]) ? $options["async"] : false), + "debug" => $debug, + "startts" => $startts, + "timeout" => $timeout, + "waituntil" => -1.0, + "data" => "", + "code" => 0, + "expectedcode" => 0, + "expectederror" => "", + "response" => "", + "fromaddrs" => $tempfromaddrs, + "toaddrs" => $temptoaddrs, + "message" => $message, + "secure" => $secure, + + "state" => "connecting", + + "options" => $options, + "result" => $result + ); + + // Return the state for async calls. Caller must call ProcessState(). + if ($state["async"]) return array("success" => true, "state" => $state); + + // Run through all of the valid states and return the result. + return self::ProcessState($state); + } + + // Has to be public so that TagFilter can successfully call. + public static function SMTP_HTMLTagFilter($stack, &$content, $open, $tagname, &$attrs, $options) + { + $content = str_replace(array(" ", " ", "\xC2\xA0"), array(" ", " ", " "), $content); + $content = str_replace("&", "&", $content); + $content = str_replace(""", "\"", $content); + + if ($tagname === "head") return array("keep_tag" => false, "keep_interior" => false); + if ($tagname === "style") return array("keep_tag" => false, "keep_interior" => false); + if ($tagname === "script") return array("keep_tag" => false, "keep_interior" => false); + if ($tagname === "a" && (!isset($attrs["href"]) || trim($attrs["href"]) === "")) return array("keep_tag" => false, "keep_interior" => false); + if ($tagname === "/a" && $stack[0]["keep_interior"]) + { + if ($stack[0]["attrs"]["href"] === trim($content)) $content = " [ " . trim($content) . " ] "; + else if (trim($content) !== "") $content = " " . trim($content) . " (" . trim($stack[0]["attrs"]["href"]) . ") "; + } + if ($tagname === "img") + { + if (!isset($attrs["src"])) $attrs["src"] = ""; + + if (isset($attrs["alt"]) && trim($attrs["alt"]) !== "" && trim($attrs["alt"]) !== $attrs["src"]) $content .= trim($attrs["alt"]) . "\n\n"; + } + + if ($tagname === "table" || $tagname === "blockquote" || $tagname === "ul") self::$depths[] = $tagname; + if ($tagname === "ol") self::$depths[] = 1; + + if (trim($content) !== "") + { + if ($tagname === "/tr") $content = ltrim($content) . "\n\n"; + if ($tagname === "/th") $content = "*" . ltrim($content) . "*\n"; + if ($tagname === "/td") $content = ltrim($content) . "\n"; + if ($tagname === "/div") $content = ltrim($content) . "\n"; + if ($tagname === "/li") $content = "\n" . (count(self::$depths) && is_int(self::$depths[count(self::$depths) - 1]) ? sprintf("%d. ", self::$depths[count(self::$depths) - 1]++) : "- ") . ltrim($content) . "\n"; + if ($tagname === "br") $content .= "\n"; + if ($tagname === "/h1" || $tagname === "/h2" || $tagname === "/h3") $content = "*" . trim($content) . "*\n\n"; + if ($tagname === "/h4" || $tagname === "/h5" || $tagname === "/h6") $content = "*" . trim($content) . "*\n"; + if ($tagname === "/i" || $tagname === "/em") $content = " _" . trim($content) . "_ "; + if ($tagname === "/b" || $tagname === "/strong") $content = " *" . trim($content) . "* "; + if ($tagname === "/p") $content = "\n\n" . trim($content) . "\n\n"; + if ($tagname === "/blockquote") $content = "------------------------\n" . trim($content) . "\n------------------------\n"; + if ($tagname === "/ul" || $tagname === "/ol" || $tagname === "/table" || $tagname === "/blockquote") + { + // Indent the lines of content varying amounts depending on final depth. + $prefix = ""; + if ($tagname === "/table") $prefix .= "\xFF\xFF"; + if ($tagname === "/ul" || $tagname === "/ol") $prefix .= "\xFF\xFF" . (count(self::$depths) > 1 ? "\xFF\xFF" : ""); + if ($tagname === "/blockquote") $prefix .= "\xFF\xFF\xFF\xFF"; + + $lines = explode("\n", $content); + foreach ($lines as $num => $line) + { + if (trim($line) !== "") + { + if ($line{0} !== "\xFF" && (($tagname === "/ul" && $line{0} !== "-") || ($tagname === "/ol" && !(int)$line{0}))) $prefix2 = "\xFF\xFF"; + else $prefix2 = ""; + + $lines[$num] = $prefix . $prefix2 . trim($line); + } + } + $content = "\n\n" . implode("\n", $lines) . "\n\n"; + } + if ($tagname === "/pre") $content = "\n\n" . $content . "\n\n"; + } + + if ($tagname === "/table" || $tagname === "/blockquote" || $tagname === "/ul" || $tagname === "/ol") array_pop(self::$depths); + + return array("keep_tag" => false); + } + + // Has to be public so that TagFilter can successfully call. + public static function SMTP_HTMLContentFilter($stack, $result, &$content, $options) + { + if (TagFilter::GetParentPos($stack, "pre") === false) + { + $content = preg_replace('/\s{2,}/', " ", str_replace(array("\r\n", "\n", "\r", "\t"), " ", $content)); + if ($result !== "" && substr($result, -1) === "\n") $content = trim($content); + } + } + + public static function ConvertHTMLToText($data) + { + self::$depths = array(); + + // Load TagFilter. + if (!class_exists("TagFilter")) require_once str_replace("\\", "/", dirname(__FILE__)) . "/tag_filter.php"; + + $data = UTF8::MakeValid($data); + + $options = TagFilter::GetHTMLOptions(); + $options["tag_callback"] = "SMTP::SMTP_HTMLTagFilter"; + $options["content_callback"] = "SMTP::SMTP_HTMLContentFilter"; + + $data = TagFilter::Run($data, $options); + + $data = str_replace("\xFF", " ", $data); + + $data = UTF8::MakeValid($data); + + return $data; + } + + private static function MIME_RandomString($length) + { + $lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + $result = ""; + + while ($length) + { + $result .= $lookup[mt_rand(0, 61)]; + + $length--; + } + + return $result; + } + + public static function SendEmail($fromaddr, $toaddr, $subject, $options = array()) + { + $subject = str_replace("\r", " ", $subject); + $subject = str_replace("\n", " ", $subject); + if (!UTF8::IsASCII($subject)) $subject = self::ConvertToRFC1342($subject); + + $replytoaddr = (isset($options["replytoaddr"]) ? $options["replytoaddr"] : ""); + $ccaddr = (isset($options["ccaddr"]) ? $options["ccaddr"] : ""); + $bccaddr = (isset($options["bccaddr"]) ? $options["bccaddr"] : ""); + $headers = (isset($options["headers"]) ? $options["headers"] : ""); + $textmessage = (isset($options["textmessage"]) ? $options["textmessage"] : ""); + $htmlmessage = (isset($options["htmlmessage"]) ? $options["htmlmessage"] : ""); + $attachments = (isset($options["attachments"]) ? $options["attachments"] : array()); + + $messagetoaddr = self::EmailAddressesToEmailHeaders($toaddr, "To", true, false, $options); + $replytoaddr = self::EmailAddressesToEmailHeaders($replytoaddr, "Reply-To", false, false, $options); + if ($replytoaddr == "") $replytoaddr = self::EmailAddressesToEmailHeaders($fromaddr, "Reply-To", false, false, $options); + $messagefromaddr = self::EmailAddressesToEmailHeaders($fromaddr, "From", false, false, $options); + if ($messagefromaddr == "" && $replytoaddr == "") return array("success" => false, "error" => self::SMTP_Translate("From address is invalid."), "errorcode" => "invalid_from_address", "info" => $fromaddr); + if ($ccaddr != "") $toaddr .= ", " . $ccaddr; + $ccaddr = self::EmailAddressesToEmailHeaders($ccaddr, "Cc", true, false, $options); + if ($bccaddr != "") $toaddr .= ", " . $bccaddr; + $bccaddr = self::EmailAddressesToEmailHeaders($bccaddr, "Bcc", true, false, $options); + + if ($htmlmessage == "" && !count($attachments)) + { + // Plain-text e-mail. + $destheaders = ""; + $destheaders .= $messagefromaddr; + if ($headers != "") $destheaders .= $headers; + $destheaders .= "MIME-Version: 1.0\r\n"; + if (!isset($options["usemail"]) || !$options["usemail"]) $destheaders .= $messagetoaddr; + if ($replytoaddr != "") $destheaders .= $replytoaddr; + if ($ccaddr != "") $destheaders .= $ccaddr; + if ($bccaddr != "") $destheaders .= $bccaddr; + if (!isset($options["usemail"]) || !$options["usemail"]) $destheaders .= "Subject: " . $subject . "\r\n"; + $destheaders .= "Content-Type: text/plain; charset=UTF-8\r\n"; + $destheaders .= "Content-Transfer-Encoding: quoted-printable\r\n"; + + $message = self::ConvertEmailMessageToRFC1341($textmessage); + } + else + { + // MIME e-mail (HTML, text, attachments). + $mimeboundary = "--------" . self::MIME_RandomString(25); + $destheaders = ""; + $destheaders .= $messagefromaddr; + if ($headers != "") $destheaders .= $headers; + $destheaders .= "MIME-Version: 1.0\r\n"; + if (!isset($options["usemail"]) || !$options["usemail"]) $destheaders .= $messagetoaddr; + if ($replytoaddr != "") $destheaders .= $replytoaddr; + if ($ccaddr != "") $destheaders .= $ccaddr; + if ($bccaddr != "") $destheaders .= $bccaddr; + if (!isset($options["usemail"]) || !$options["usemail"]) $destheaders .= "Subject: " . $subject . "\r\n"; + if (count($attachments) && isset($options["inlineattachments"]) && $options["inlineattachments"]) $destheaders .= "Content-Type: multipart/related; boundary=\"" . $mimeboundary . "\"; type=\"multipart/alternative\"\r\n"; + else if (count($attachments)) $destheaders .= "Content-Type: multipart/mixed; boundary=\"" . $mimeboundary . "\"\r\n"; + else if ($textmessage != "" && $htmlmessage != "") $destheaders .= "Content-Type: multipart/alternative; boundary=\"" . $mimeboundary . "\"\r\n"; + else $mimeboundary = ""; + + if ($mimeboundary != "") $mimecontent = "This is a multi-part message in MIME format.\r\n"; + else $mimecontent = ""; + + if ($textmessage == "" || $htmlmessage == "" || !count($attachments)) $mimeboundary2 = $mimeboundary; + else + { + $mimeboundary2 = "--------" . self::MIME_RandomString(25); + $mimecontent .= "--" . $mimeboundary . "\r\n"; + $mimecontent .= "Content-Type: multipart/alternative; boundary=\"" . $mimeboundary2 . "\"\r\n"; + $mimecontent .= "\r\n"; + } + + if ($textmessage != "") + { + if ($mimeboundary2 != "") + { + $mimecontent .= "--" . $mimeboundary2 . "\r\n"; + $mimecontent .= "Content-Type: text/plain; charset=UTF-8\r\n"; + $mimecontent .= "Content-Transfer-Encoding: quoted-printable\r\n"; + $mimecontent .= "\r\n"; + } + else + { + $destheaders .= "Content-Type: text/plain; charset=UTF-8\r\n"; + $destheaders .= "Content-Transfer-Encoding: quoted-printable\r\n"; + } + $message = self::ConvertEmailMessageToRFC1341($textmessage); + $mimecontent .= $message; + $mimecontent .= "\r\n"; + } + + if ($htmlmessage != "") + { + if ($mimeboundary2 != "") + { + $mimecontent .= "--" . $mimeboundary2 . "\r\n"; + $mimecontent .= "Content-Type: text/html; charset=UTF-8\r\n"; + $mimecontent .= "Content-Transfer-Encoding: quoted-printable\r\n"; + $mimecontent .= "\r\n"; + } + else + { + $destheaders .= "Content-Type: text/html; charset=UTF-8\r\n"; + $destheaders .= "Content-Transfer-Encoding: quoted-printable\r\n"; + } + $message = self::ConvertEmailMessageToRFC1341($htmlmessage); + $mimecontent .= $message; + $mimecontent .= "\r\n"; + } + + if ($mimeboundary2 != "" && $mimeboundary != $mimeboundary2) $mimecontent .= "--" . $mimeboundary2 . "--\r\n"; + + // Process the attachments. + $y = count($attachments); + for ($x = 0; $x < $y; $x++) + { + $mimecontent .= "--" . $mimeboundary . "\r\n"; + $type = str_replace("\r", "", $attachments[$x]["type"]); + $type = str_replace("\n", "", $type); + $type = UTF8::ConvertToASCII($type); + if (!isset($attachments[$x]["name"])) $name = ""; + else + { + $name = str_replace("\r", "", $attachments[$x]["name"]); + $name = str_replace("\n", "", $name); + $name = self::FilenameSafe($name); + } + + if (!isset($attachments[$x]["location"])) $location = ""; + else + { + $location = str_replace("\r", "", $attachments[$x]["location"]); + $location = str_replace("\n", "", $location); + $location = UTF8::ConvertToASCII($location); + } + + if (!isset($attachments[$x]["cid"])) $cid = ""; + else + { + $cid = str_replace("\r", "", $attachments[$x]["cid"]); + $cid = str_replace("\n", "", $cid); + $cid = UTF8::ConvertToASCII($cid); + } + $mimecontent .= "Content-Type: " . $type . ($name != "" ? "; name=\"" . $name . "\"" : "") . "\r\n"; + if ($cid != "") $mimecontent .= "Content-ID: <" . $cid . ">\r\n"; + if ($location != "") $mimecontent .= "Content-Location: " . $location . "\r\n"; + $mimecontent .= "Content-Transfer-Encoding: base64\r\n"; + if ($name != "") $mimecontent .= "Content-Disposition: inline; filename=\"" . $name . "\"\r\n"; + $mimecontent .= "\r\n"; + $mimecontent .= chunk_split(base64_encode($attachments[$x]["data"])); + $mimecontent .= "\r\n"; + } + + if ($mimeboundary != "") $mimecontent .= "--" . $mimeboundary . "--\r\n"; + $message = $mimecontent; + } + + if (isset($options["returnresults"]) && $options["returnresults"]) return array("success" => true, "toaddr" => $toaddr, "fromaddr" => $fromaddr, "headers" => $destheaders, "subject" => $subject, "message" => $message); + else if (isset($options["usemail"]) && $options["usemail"]) + { + $result = mail($toaddr, $subject, self::ReplaceNewlines("\n", $message), $destheaders); + if (!$result) return array("success" => false, "error" => self::SMTP_Translate("PHP mail() call failed."), "errorcode" => "mail_call_failed"); + + return array("success" => true); + } + else + { + return self::SendSMTPEmail($toaddr, $fromaddr, $destheaders . "\r\n" . $message, $options); + } + } + } +?> \ No newline at end of file diff --git a/signup/email/utf8.php b/signup/email/utf8.php new file mode 100644 index 0000000..d5f878b --- /dev/null +++ b/signup/email/utf8.php @@ -0,0 +1,208 @@ + 1) $tempchr2 = ord($data[$x + 1]); + else $tempchr2 = 0x00; + if ($y - $x > 2) $tempchr3 = ord($data[$x + 2]); + else $tempchr3 = 0x00; + if ($y - $x > 3) $tempchr4 = ord($data[$x + 3]); + else $tempchr4 = 0x00; + if ($tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D || ($tempchr >= 0x20 && $tempchr <= 0x7E)) + { + // ASCII minus control and special characters. + $result .= chr($tempchr); + $x++; + } + else if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) + { + // Non-overlong (2 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $x += 2; + } + else if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) + { + // Non-overlong (3 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $result .= chr($tempchr3); + $x += 3; + } + else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) + { + // Normal/straight (3 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $result .= chr($tempchr3); + $x += 3; + } + else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) + { + // Non-surrogates (3 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $result .= chr($tempchr3); + $x += 3; + } + else if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) + { + // Planes 1-3 (4 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $result .= chr($tempchr3); + $result .= chr($tempchr4); + $x += 4; + } + else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) + { + // Planes 4-15 (4 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $result .= chr($tempchr3); + $result .= chr($tempchr4); + $x += 4; + } + else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) + { + // Plane 16 (4 bytes). + $result .= chr($tempchr); + $result .= chr($tempchr2); + $result .= chr($tempchr3); + $result .= chr($tempchr4); + $x += 4; + } + else $x++; + } + + return $result; + } + + public static function IsValid($data) + { + $x = 0; + $y = strlen($data); + while ($x < $y) + { + $tempchr = ord($data[$x]); + if ($y - $x > 1) $tempchr2 = ord($data[$x + 1]); + else $tempchr2 = 0x00; + if ($y - $x > 2) $tempchr3 = ord($data[$x + 2]); + else $tempchr3 = 0x00; + if ($y - $x > 3) $tempchr4 = ord($data[$x + 3]); + else $tempchr4 = 0x00; + if ($tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D || ($tempchr >= 0x20 && $tempchr <= 0x7E)) $x++; + else if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 2; + else if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) $x += 3; + else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) $x += 3; + else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) $x += 3; + else if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) $x += 4; + else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) $x += 4; + else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) $x += 4; + else return false; + } + + return true; + } + + // Locates the next UTF8 character in a UTF8 string. + // Set Pos and Size to 0 to start at the beginning. + // Returns false at the end of the string or bad UTF8 character. Otherwise, returns true. + public static function NextChrPos(&$data, $datalen, &$pos, &$size) + { + $pos += $size; + $size = 0; + $x = $pos; + $y = $datalen; + if ($x >= $y) return false; + + $tempchr = ord($data[$x]); + if ($y - $x > 1) $tempchr2 = ord($data[$x + 1]); + else $tempchr2 = 0x00; + if ($y - $x > 2) $tempchr3 = ord($data[$x + 2]); + else $tempchr3 = 0x00; + if ($y - $x > 3) $tempchr4 = ord($data[$x + 3]); + else $tempchr4 = 0x00; + if ($tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D || ($tempchr >= 0x20 && $tempchr <= 0x7E)) $size = 1; + else if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $size = 2; + else if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) $size = 3; + else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) $size = 3; + else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF)) $size = 3; + else if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) $size = 4; + else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) $size = 4; + else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF)) $size = 4; + else return false; + + return true; + } + + // Determines if a UTF8 string can also be viewed as ASCII. + public static function IsASCII($data) + { + $pos = 0; + $size = 0; + $y = strlen($data); + while (self::NextChrPos($data, $y, $pos, $size) && $size == 1) {} + if ($pos < $y || $size > 1) return false; + + return true; + } + + // Returns the number of characters in a UTF8 string. + public static function strlen($data) + { + $num = 0; + $pos = 0; + $size = 0; + $y = strlen($data); + while (self::NextChrPos($data, $y, $pos, $size)) $num++; + + return $num; + } + + // Converts a UTF8 string to ASCII and drops bad UTF8 and non-ASCII characters in the process. + public static function ConvertToASCII($data) + { + $result = ""; + + $pos = 0; + $size = 0; + $y = strlen($data); + while ($pos < $y) + { + if (self::NextChrPos($data, $y, $pos, $size) && $size == 1) $result .= $data[$pos]; + else if (!$size) $size = 1; + } + + return $result; + } + + // Converts UTF8 characters in a string to HTML entities. + public static function ConvertToHTML($data) + { + return preg_replace_callback('/([\xC0-\xF7]{1,1}[\x80-\xBF]+)/', 'UTF8::ConvertToHTML__Callback', $data); + } + + private static function ConvertToHTML__Callback($data) + { + $data = $data[1]; + $num = 0; + $data = str_split(strrev(chr((ord(substr($data, 0, 1)) % 252 % 248 % 240 % 224 % 192) + 128) . substr($data, 1))); + foreach ($data as $k => $v) $num += (ord($v) % 128) * pow(64, $k); + + return "&#" . $num . ";"; + } + } +?> \ No newline at end of file diff --git a/signup/signup-handler.php b/signup/signup-handler.php index ebeda25..4e9df7d 100644 --- a/signup/signup-handler.php +++ b/signup/signup-handler.php @@ -1,8 +1,6 @@ \ No newline at end of file +?>