diff --git a/footer.php b/footer.php index 5f85cab..c7a2628 100644 --- a/footer.php +++ b/footer.php @@ -1 +1,3 @@ + + diff --git a/header.php b/header.php index 34971d8..9aee802 100644 --- a/header.php +++ b/header.php @@ -1,6 +1,9 @@ + + + <?=isset($title) ? $title : "Welcome to ~tilde.club~"?> - + 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/index.php b/signup/index.php index 71625a4..8d94175 100644 --- a/signup/index.php +++ b/signup/index.php @@ -1,2 +1,53 @@ + +

devmode!! please do not use yet!!

+

sign up to join tilde.club

+ +

we're excited you're here! let's get you signed up!

+

fill out this form and we'll get back to you with account info

+ + + + + +
+
+ + +
+

your desired username (numbers and lowercase letters only, no spaces)

+ " type="text" required> +
+ +
+

email to contact you with account info

+ " type="text" required> +
+ +
+

what interests you about tilde.club? we want to make sure you're a real human being :)

+ +
+ +
+

SSH public key

+ +

if you don't have a key, don't worry! check out our guide to ssh keys and make sure that you only put your pubkey here

+
+ +

+ signing up implies that you agree to abide by the rule of NO DRAMA +
+ no drama. be respectful. have fun. we're all trying, and we're all in this together :) +

+ + + +
+ +
+ +please fill in your desired username"; + + if (strlen($name) > 32) + $message .= "
  • username too long (32 character max)
  • "; + + if (!preg_match('/^[a-z][a-z0-9]{2,31}$/', $name)) + $message .= "
  • username contains invalid characters (lowercase only, must start with a letter)
  • "; + + if ($_REQUEST["sshkey"] == "" || mb_substr($_REQUEST["sshkey"], 0, 4) !== "ssh-") + $message .= '
  • ssh key required: please create one and submit the public key. ' + . 'see our ssh wiki or ' + . 'hop on irc and ask for help
  • '; + + if ($_REQUEST["interest"] == "") + $message .= "
  • please explain why you're interested so we can make sure you're a real human being
  • "; + + if (posix_getpwnam($name) || forbidden_name($name)) + $message .= "
  • sorry, the username $name is unavailable
  • "; + + // Check the e-mail address. + $email = trim($_REQUEST["email"]); + if ($email == "") + $message .= "
  • please fill in your email address
  • "; + else { + $result = SMTP::MakeValidEmailAddress($_REQUEST["email"]); + if (!$result["success"]) + $message .= "
  • invalid email address: " . htmlspecialchars($result["error"]) . "
  • "; + elseif ($result["email"] != $email) + $message .= "
  • invalid email address. did you mean: " . htmlspecialchars($result["email"]) . "
  • "; + } + + + // no validation errors + if ($message == "") { + $msgbody = " +username: {$_REQUEST["username"]} +email: {$_REQUEST["email"]} +reason: {$_REQUEST["interest"]} + +makeuser {$_REQUEST["username"]} {$_REQUEST["email"]} \"{$_REQUEST["sshkey"]}\" +"; + + if (mail('root', 'new tilde.club signup', $msgbody)) { + echo ''; + } else { + echo ''; + } + + } else { + ?> + + + diff --git a/style.css b/style.css index 2b4e9a9..4826671 100644 --- a/style.css +++ b/style.css @@ -33,6 +33,18 @@ h1 {text-transform:uppercase;font-weight:bold; animation-iteration-count: infinite; } +input[type="text"], textarea { + background-color : #333; + color: darkorange; +} + +div.alert-warning { + background-color: darkred; +} +div.alert-success { + background-color: darkgreen; +} + @-moz-keyframes blinker { 0% { opacity: 1.0; } 50% { opacity: 0.75; } diff --git a/wiki/README.md b/wiki/README.md new file mode 100644 index 0000000..c6035d2 --- /dev/null +++ b/wiki/README.md @@ -0,0 +1,10 @@ +# tilde.club wiki + +to write an article, make a markdown file in source/ and fill out the appropriate +metadata keys (see source/ssh.md). + +run + ./build-wiki.sh + +before committing, and open a PR! + diff --git a/wiki/build-wiki.sh b/wiki/build-wiki.sh new file mode 100755 index 0000000..d970269 --- /dev/null +++ b/wiki/build-wiki.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +for page in source/*.md; do + pagename=$(basename $page ".md") + pandoc --template pandoc-template.html -o "$pagename.html" "source/$pagename.md" +done + diff --git a/wiki/index.php b/wiki/index.php new file mode 100644 index 0000000..74e3484 --- /dev/null +++ b/wiki/index.php @@ -0,0 +1,17 @@ + + +

    the tilde.club wiki

    + +

    here's the articles on our wiki:

    +
      + +
    • + +
    + + + + + + + + $for(author-meta)$ + + $endfor$ + $if(date-meta)$ + + $endif$ + $if(keywords)$ + + $endif$ + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ + + + $if(highlighting-css)$ + + $endif$ + $for(css)$ + + $endfor$ + $if(math)$ + $math$ + $endif$ + + $for(header-includes)$ + $header-includes$ + $endfor$ + + + < back to wiki home + $for(include-before)$ + $include-before$ + $endfor$ + $if(title)$ +
    +

    $title$

    + $if(subtitle)$ +

    $subtitle$

    + $endif$ + + $if(author)$ +

    authors:

    + $for(author)$ +

    ~$author$

    + $endfor$ + $endif$ + + $if(date)$ +

    $date$

    + $endif$ +
    + $endif$ + $if(toc)$ + + $endif$ + $body$ + $for(include-after)$ + $include-after$ + $endfor$ + + + diff --git a/wiki/source/ssh.md b/wiki/source/ssh.md new file mode 100644 index 0000000..6b2d5f4 --- /dev/null +++ b/wiki/source/ssh.md @@ -0,0 +1,258 @@ +--- +author: benharri +published: true +title: ssh +description: ssh tutorial and background info +category: + - main +--- + + +_or, how to tell other computers to do cool things_ + +--- + +> all users are required to use an ssh keypair for login, or will be required +to proceed with manual account recovery + +## tilde.club details + +for example, to connect to tilde.club, you can do: + +``` +ssh user@tilde.club +mosh user@tilde.club +``` + +--- + +## intro + +** if you just want to get right to a tutorial you can +[skip over this background info](#how-to-make-an-ssh-key)** + +while [tilde.club](https://tilde.club) is accessible on the web and features +lovely web pages written by its users, most interaction with tilde.club takes +place **inside the machine** that runs tilde.club as opposed to via web forms +that have an effect from **outside** tilde.club's computer. + +this is what sets tilde.club apart from most other online communities. you +connect directly to another computer from yours alongside other people and then +write your web pages, chat, and play games all via text-based interfaces right +on tilde.club's computer. + +prior to the web (which debuted in 1995) this is how pretty much all computer +stuff got done. you connected directly to a machine (usually over a direct, +physical phone line) and did your work there. + +for a long time, people used a tool called +[`telnet`](https://en.wikipedia.org/wiki/telnet) to connect to other computers. +these days we use a tool called **ssh**. + +`ssh` is a text-based tool that provides a direct connection from your computer +to another. ssh is an acronym that stands for secure shell. the _shell_ part +refers to the fact that it's a text-based tool; we use the word shell to refer +to a text-based interface that you give commands to. the _secure_ part refers +to the fact that, when you're using ssh, no one can spy on your connection to +another computer (unlike the old `telnet` command). + +**why bother with all of this?** passwords are really insecure and hard to manage. +using keys makes life easier for you, fair user (your account is less likely to +be hacked) and for me, your humble sysadmin (less administration than passwords). + +--- + +## how to make an ssh key + +SSH supports a handful of types of cryptographic keys. The most used are [RSA]( + ) and the more modern [Ed25519]( + https://en.wikipedia.org/wiki/EdDSA#Ed25519). + +RSA is the de-facto standard and is supported everywhere (just choose a big +enough key like 4096 bits to be secure). Ed25519 is designed to be faster and +smaller withouth sacrificing security, so is best suited for embedded devices +or machines with low resources. It's supported on tilde (and really on any +modern system) but you may find older systems which do not support it. + +Below you'll find instructions to generate either type (or both if you want). + +Keep in mind that these instructions leave your private keys unencrypted in +your local hard disk. So keep them private; never share them. A good solution +is to provide a password for them at creation time, but this implies entering +a password any time you used them (impractical) or use something like [ssh-agent]( + https://man.openbsd.org/ssh-agent.1) (a bit more complex) + +pick your fighter: [[mac](#mac)] | [[windows](#windows)] | [[linux](#linux)] + +--- + +### mac + +#### generating your keypair + +1. open terminal (it's in `/Applications/Utilities`) + +1. create your .ssh directory: + +```bash +mkdir -m 700 ~/.ssh +``` + +1. create your keys: + +for rsa keys: + +```bash +ssh-keygen -t rsa -b 4096 +``` + +for dd25519 keys: + +```bash +ssh-keygen -t ed25519 -a 100 +``` + +1. if you press enter to accept the defaults, your public and private key will +be located at `~/.ssh/id_rsa.pub` and `~/.ssh/id_rsa` respectively (or +`~/.ssh/id_ed25519.pub` and `~/.ssh/id_ed25519` if you chose ed25519 type) + +1. `cat ~/.ssh/id_rsa.pub` (or `cat ~/.ssh/id_ed25519.pub` for ed25519) + +1. copy the output of the last command and paste it in the sshkey field on the +signup form (or email it to [~root](mailto:root@tilde.club) if you already have an account) + +#### using your keypair + +once an admin approves your signup, you can join the tilde.club + +1. open terminal (it's in `/Applications/Utilities`) + +1. `ssh` to tilde.club: + +```bash +ssh username@tilde.club +``` + +where username is your username (~benharri would use `ssh benharri@tilde.club`) + +1. profit??? + +--- + +### windows + +there are a couple options for using ssh on windows these days. +i like to use [git bash](https://git-scm.com). + +#### generating your keypair + +choose from any of the following options: + +- [windows subsystem for linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) +- [msys2](http://www.msys2.org/) +- [git bash](https://git-scm.com) + +1. open your new shell + +1. create your .ssh directory + +```bash +mkdir .ssh +``` + +1. create your keypair + +for rsa keys: + +```bash +ssh-keygen -t rsa -b 4096 +``` + +for ed25519 keys: + +```bash +ssh-keygen -t ed25519 -a 100 +``` + +1. if you press enter to accept the defaults, your public and private key will +be located at `~/.ssh/id_rsa.pub` and `~/.ssh/id_rsa` respectively (or +`~/.ssh/id_ed25519.pub` and `~/.ssh/id_ed25519` if you chose ed25519 type) + +1. `cat ~/.ssh/id_rsa.pub` (or `cat ~/.ssh/id_ed25519.pub` for ed25519) + +1. copy the output of the last command and paste it in the sshkey field on the +signup form (or email it to [~root](mailto:root@tilde.club) if you already have an account) + +#### using your keypair + +once an admin approves your signup, you can join the tilde.club + +1. open terminal (it's in `/Applications/Utilities`) + +1. `ssh` to tilde.club: + +```bash +ssh username@tilde.club +``` + +where username is your username (~benharri would use `ssh benharri@tilde.club`) + +1. profit??? + +--- + +### linux + +there are a lot of linux distros, but `ssh` and `ssh-keygen` should be available +in almost all cases. if they're not, look up how to install ssh for your distro. + +#### generating your keypair + +1. make sure you have a `~/.ssh` directory + +```bash +mkdir -m 700 ~/.ssh +``` + +1. create your keys + +for rsa keys: + +```bash +ssh-keygen -t rsa -b 4096 +``` + +for ed25519 keys: + +```bash +ssh-keygen -t ed25519 -a 100 +``` + +1. if you press enter to accept the defaults, your public and private key will +be located at `~/.ssh/id_rsa.pub` and `~/.ssh/id_rsa` respectively (or +`~/.ssh/id_ed25519.pub` and `~/.ssh/id_ed25519` if you chose ed25519 type) + +1. `cat ~/.ssh/id_rsa.pub` (or `cat ~/.ssh/id_ed25519.pub` for ed25519) + +1. copy the output of the last command and paste it in the sshkey field on the +signup form (or email it to [root@tilde.club](mailto:root@tilde.club) if you already have an account) + +#### using your keypair + +once an admin approves your signup, you can join the tilde.club + +1. open a terminal (this depends on your distro) + +1. `ssh` to tilde.club: + +```bash +ssh username@tilde.club +``` + +where username is your username (~benharri would use `ssh benharri@tilde.club`) + +1. profit??? + +--- + +this tutorial is based on and uses parts of [the tilde.club ssh primer](https://github.com/tildeclub/tilde.club/blob/master/docs/ssh.md) and [the tilde.town ssh guide](https://tilde.town/wiki/ssh.html). diff --git a/wiki/ssh.html b/wiki/ssh.html new file mode 100644 index 0000000..ca561cb --- /dev/null +++ b/wiki/ssh.html @@ -0,0 +1,221 @@ + + + + + + + + ssh + + + + + + + < back to wiki home +
    +

    ssh

    + +

    authors:

    +

    ~benharri

    + +
    +

    or, how to tell other computers to do cool things

    +
    +
    +

    all users are required to use an ssh keypair for login, or will be required to proceed with manual account recovery

    +
    +

    tilde.club details

    +

    for example, to connect to tilde.club, you can do:

    +
    ssh user@tilde.club
    +mosh user@tilde.club
    +
    +

    intro

    +

    ** if you just want to get right to a tutorial you can skip over this background info**

    +

    while tilde.club is accessible on the web and features lovely web pages written by its users, most interaction with tilde.club takes place inside the machine that runs tilde.club as opposed to via web forms that have an effect from outside tilde.club’s computer.

    +

    this is what sets tilde.club apart from most other online communities. you connect directly to another computer from yours alongside other people and then write your web pages, chat, and play games all via text-based interfaces right on tilde.club’s computer.

    +

    prior to the web (which debuted in 1995) this is how pretty much all computer stuff got done. you connected directly to a machine (usually over a direct, physical phone line) and did your work there.

    +

    for a long time, people used a tool called telnet to connect to other computers. these days we use a tool called ssh.

    +

    ssh is a text-based tool that provides a direct connection from your computer to another. ssh is an acronym that stands for secure shell. the shell part refers to the fact that it’s a text-based tool; we use the word shell to refer to a text-based interface that you give commands to. the secure part refers to the fact that, when you’re using ssh, no one can spy on your connection to another computer (unlike the old telnet command).

    +

    why bother with all of this? passwords are really insecure and hard to manage. using keys makes life easier for you, fair user (your account is less likely to be hacked) and for me, your humble sysadmin (less administration than passwords).

    +
    +

    how to make an ssh key

    +

    SSH supports a handful of types of cryptographic keys. The most used are RSA and the more modern Ed25519.

    +

    RSA is the de-facto standard and is supported everywhere (just choose a big enough key like 4096 bits to be secure). Ed25519 is designed to be faster and smaller withouth sacrificing security, so is best suited for embedded devices or machines with low resources. It’s supported on tilde (and really on any modern system) but you may find older systems which do not support it.

    +

    Below you’ll find instructions to generate either type (or both if you want).

    +

    Keep in mind that these instructions leave your private keys unencrypted in your local hard disk. So keep them private; never share them. A good solution is to provide a password for them at creation time, but this implies entering a password any time you used them (impractical) or use something like ssh-agent (a bit more complex)

    +

    pick your fighter: [mac] | [windows] | [linux]

    +
    +

    mac

    +

    generating your keypair

    +
      +
    1. open terminal (it’s in /Applications/Utilities)

    2. +
    3. create your .ssh directory:

    4. +
    + +
      +
    1. create your keys:
    2. +
    +

    for rsa keys:

    + +

    for dd25519 keys:

    + +
      +
    1. if you press enter to accept the defaults, your public and private key will be located at ~/.ssh/id_rsa.pub and ~/.ssh/id_rsa respectively (or ~/.ssh/id_ed25519.pub and ~/.ssh/id_ed25519 if you chose ed25519 type)

    2. +
    3. cat ~/.ssh/id_rsa.pub (or cat ~/.ssh/id_ed25519.pub for ed25519)

    4. +
    5. copy the output of the last command and paste it in the sshkey field on the signup form (or email it to ~root if you already have an account)

    6. +
    +

    using your keypair

    +

    once an admin approves your signup, you can join the tilde.club

    +
      +
    1. open terminal (it’s in /Applications/Utilities)

    2. +
    3. ssh to tilde.club:

    4. +
    + +

    where username is your username (~benharri would use ssh benharri@tilde.club)

    +
      +
    1. profit???
    2. +
    +
    +

    windows

    +

    there are a couple options for using ssh on windows these days. i like to use git bash.

    +

    generating your keypair

    +

    choose from any of the following options:

    + +
      +
    1. open your new shell

    2. +
    3. create your .ssh directory

    4. +
    + +
      +
    1. create your keypair
    2. +
    +

    for rsa keys:

    + +

    for ed25519 keys:

    + +
      +
    1. if you press enter to accept the defaults, your public and private key will be located at ~/.ssh/id_rsa.pub and ~/.ssh/id_rsa respectively (or ~/.ssh/id_ed25519.pub and ~/.ssh/id_ed25519 if you chose ed25519 type)

    2. +
    3. cat ~/.ssh/id_rsa.pub (or cat ~/.ssh/id_ed25519.pub for ed25519)

    4. +
    5. copy the output of the last command and paste it in the sshkey field on the signup form (or email it to ~root if you already have an account)

    6. +
    +

    using your keypair

    +

    once an admin approves your signup, you can join the tilde.club

    +
      +
    1. open terminal (it’s in /Applications/Utilities)

    2. +
    3. ssh to tilde.club:

    4. +
    + +

    where username is your username (~benharri would use ssh benharri@tilde.club)

    +
      +
    1. profit???
    2. +
    +
    +

    linux

    +

    there are a lot of linux distros, but ssh and ssh-keygen should be available in almost all cases. if they’re not, look up how to install ssh for your distro.

    +

    generating your keypair

    +
      +
    1. make sure you have a ~/.ssh directory
    2. +
    + +
      +
    1. create your keys
    2. +
    +

    for rsa keys:

    + +

    for ed25519 keys:

    + +
      +
    1. if you press enter to accept the defaults, your public and private key will be located at ~/.ssh/id_rsa.pub and ~/.ssh/id_rsa respectively (or ~/.ssh/id_ed25519.pub and ~/.ssh/id_ed25519 if you chose ed25519 type)

    2. +
    3. cat ~/.ssh/id_rsa.pub (or cat ~/.ssh/id_ed25519.pub for ed25519)

    4. +
    5. copy the output of the last command and paste it in the sshkey field on the signup form (or email it to root@tilde.club if you already have an account)

    6. +
    +

    using your keypair

    +

    once an admin approves your signup, you can join the tilde.club

    +
      +
    1. open a terminal (this depends on your distro)

    2. +
    3. ssh to tilde.club:

    4. +
    + +

    where username is your username (~benharri would use ssh benharri@tilde.club)

    +
      +
    1. profit???
    2. +
    +
    +

    this tutorial is based on and uses parts of the tilde.club ssh primer and the tilde.town ssh guide.

    + + +