*/ class syntax_plugin_dig extends SyntaxPlugin { /** @inheritdoc */ public function getType() { return 'substition'; } /** @inheritdoc */ public function getPType() { return 'block'; } /** @inheritdoc */ public function getSort() { return 333; } /** @inheritdoc */ public function connectTo($mode) { $this->Lexer->addSpecialPattern('\n.*?\n', $mode, 'plugin_dig'); } /** @inheritdoc */ public function handle($match, $state, $pos, Doku_Handler $handler) { $lines = explode("\n", $match); array_shift($lines); // skip opening tag array_pop($lines); // skip closing tag return linesToHash($lines); } /** @inheritdoc */ public function render($mode, Doku_Renderer $R, $data) { if ($mode == 'metadata') return false; $R->table_open(); $R->tablethead_open(); $R->tablerow_open(); $R->tableheader_open(); $R->cdata($this->getLang('host')); $R->tableheader_close(); $R->tableheader_open(); $R->cdata($this->getLang('ip')); $R->tableheader_close(); $R->tableheader_open(); $R->cdata($this->getLang('ns')); $R->tableheader_close(); $R->tableheader_open(); $R->cdata($this->getLang('ssl')); $R->tableheader_close(); $R->tablerow_close(); $R->tablethead_close(); $R->tabletbody_open(); foreach ($data as $domain => $comment) { $R->tablerow_open(); $this->renderCell($R, [$domain, $comment]); try { $dns = $this->getDNS($domain); $this->renderCell($R, $dns['ip']); $this->renderCell($R, $dns['ns']); } catch (Exception $e) { $this->renderCell($R, $e->getMessage(), 2); } try { $ssl = $this->getSSL($domain); $this->renderCell( $R, [ 'valid' => $ssl['date_valid'] && $ssl['domain_valid'] ? '✔️' : '❌', 'until' => date('Y-m-d', $ssl['date_to']), 'days' => floor(($ssl['date_to'] - time()) / (24 * 60 * 60)), 'issuer' => $ssl['issuer'], 'domains' => count($ssl['domains']), ] ); } catch (Exception $e) { $this->renderCell($R, $e->getMessage()); } $R->tablerow_close(); } $R->tabletbody_close(); $R->tabletfoot_open(); $R->tablerow_open(); $R->tablecell_open(4); $R->cdata($this->getLang('lastupdate') . ' ' . date('Y-m-d H:i:s')); $R->tablecell_close(); $R->tablerow_close(); $R->tabletfoot_close(); $R->table_close(); return true; } /** * Get the DNS information for a domain * * @param string $domain * @return array * @throws Exception if the DNS lookup fails */ protected function getDNS($domain) { $info = [ 'ip' => [], 'ns' => [], ]; $record = dns_get_record($domain, DNS_ALL); if (!$record) throw new Exception($this->getLang('dnsfail')); foreach ($record as $r) { switch ($r['type']) { case 'A': $info['ip']['IP'] = $r['ip']; break; case 'AAAA': $info['ip']['IPv6'] = $r['ipv6']; break; case 'CNAME': $info['ip']['CNAME'] = $r['target']; break; case 'SOA': $info['ns']['NS'] = $r['mname']; break; case 'MX': $info['ns']['MX'] = $r['target']; break; } } return $info; } /** * Get the certificate information for a domain * * @param string $domain * @return array * @throws Exception if the SSL lookup fails */ protected function getSSL($domain) { if (!function_exists('openssl_x509_parse')) { throw new Exception($this->getLang('sslfail') . ': ' . 'openssl not available in your PHP installation'); } $context = stream_context_create( ["ssl" => ["capture_peer_cert" => true, 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true]] ); $read = @stream_socket_client( "ssl://" . $domain . ":443", $errno, $errstr, 15, STREAM_CLIENT_CONNECT, $context ); if ($errstr) throw new Exception($this->getLang('sslfail') . ': ' . $errstr, $errno); $cert = stream_context_get_params($read); $certinfo = openssl_x509_parse($cert['options']['ssl']['peer_certificate']); $issuer = $certinfo['issuer']['O'] ?? implode(' ', $certinfo['issuer']); $domains = array_merge( [$certinfo['subject']['CN']], explode(',', $certinfo['extensions']['subjectAltName']) ); $domains = array_map(static fn($d) => preg_replace('/^DNS:/', '', trim($d)), $domains); return [ 'date_from' => $certinfo['validFrom_time_t'], 'date_to' => $certinfo['validTo_time_t'], 'date_valid' => $certinfo['validFrom_time_t'] < time() && time() < $certinfo['validTo_time_t'], 'issuer' => $issuer, 'domains' => $domains, 'domain_valid' => in_array($domain, $domains), ]; } /** * @param Doku_Renderer $R * @param string|array $data * @param int $colspan */ protected function renderCell($R, $data, $colspan = 1) { $R->tablecell_open($colspan); if (is_array($data)) { foreach ($data as $key => $item) { if (!is_numeric($key)) { $R->cdata($key . ': '); } $R->cdata($item); $R->linebreak(); } } else { $R->cdata($data); } $R->tablecell_close(); } }