diff --git a/.env.example b/.env.example index 4f99eaf..92b837a 100644 --- a/.env.example +++ b/.env.example @@ -18,6 +18,9 @@ ECHOIP_HOST=ip.343.re KMS_HOST=kms.343.re KMS_VLMCS=/usr/bin/vlmcs +# Whois Program +WHOIS_TOOL=/usr/bin/whois + # ChinaZ API ICP_KEY= diff --git a/functions/DNS.php b/functions/DNS.php index 98f8b72..c2e5d14 100644 --- a/functions/DNS.php +++ b/functions/DNS.php @@ -67,6 +67,11 @@ class DNS { // DNS解析功能 } return inet_ntop(inet_pton(substr($ipv6, 0, -1))); } + + public function zipIPv6($ipv6) { // 压缩IPv6地址 + $ipv6 = $this->ip2long6($ipv6); + return $this->long2ip6($ipv6); + } } ?> diff --git a/functions/Domain.php b/functions/Domain.php index 8bc4adc..4824de6 100644 --- a/functions/Domain.php +++ b/functions/Domain.php @@ -95,6 +95,14 @@ class Domain { // 域名相关功能 $info['site'] = json_decode(base64_decode($info['site']), true); return $info; } + + public function getWhoisServer($tld) { // 查询TLD的whois服务器 + $db = new SqliteDB($this->tldDB); + $res = $db->query('SELECT * FROM `iana` WHERE tld="' . $tld . '";'); + $info = $res->fetchArray(SQLITE3_ASSOC); + if (!$info) { return null; } // 查无该TLD + return $info['whois']; // 返回查询结果 + } } ?> diff --git a/models/whoisQuery.php b/models/whoisQuery.php index 7186303..d2ff070 100644 --- a/models/whoisQuery.php +++ b/models/whoisQuery.php @@ -1,170 +1,81 @@ "whois.verisign-grs.com", - "net" => "whois.verisign-grs.com", - "org" => "whois.pir.org", - "info" => "whois.afilias.info", - "biz" => "whois.neulevel.biz", - "us" => "whois.nic.us", - "uk" => "whois.nic.uk", - "ca" => "whois.cira.ca", - "tel" => "whois.nic.tel", - "ie" => "whois.iedr.ie", - "it" => "whois.nic.it", - "li" => "whois.nic.li", - "no" => "whois.norid.no", - "cc" => "whois.nic.cc", - "eu" => "whois.eu", - "nu" => "whois.nic.nu", - "au" => "whois.aunic.net", - "de" => "whois.denic.de", - "ws" => "whois.worldsite.ws", - "sc" => "whois2.afilias-grs.net", - "mobi" => "whois.dotmobiregistry.net", - "pro" => "whois.registrypro.pro", - "edu" => "whois.educause.net", - "tv" => "whois.nic.tv", - "travel" => "whois.nic.travel", - "name" => "whois.nic.name", - "in" => "whois.inregistry.net", - "me" => "whois.nic.me", - "at" => "whois.nic.at", - "be" => "whois.dns.be", - "cn" => "whois.cnnic.cn", - "asia" => "whois.nic.asia", - "ru" => "whois.ripn.ru", - "ro" => "whois.rotld.ro", - "aero" => "whois.aero", - "fr" => "whois.nic.fr", - "se" => "whois.iis.se", - "nl" => "whois.sidn.nl", - "nz" => "whois.srs.net.nz", - "mx" => "whois.nic.mx", - "tw" => "whois.apnic.net", - "ch" => "whois.nic.ch", - "hk" => "whois.hknic.net.hk", - "ac" => "whois.nic.ac", - "ae" => "whois.nic.ae", - "af" => "whois.nic.af", - "ag" => "whois.nic.ag", - "al" => "whois.ripe.net", - "am" => "whois.amnic.net", - "as" => "whois.nic.as", - "az" => "whois.ripe.net", - "ba" => "whois.ripe.net", - "bg" => "whois.register.bg", - "bi" => "whois.nic.bi", - "bj" => "www.nic.bj", - "br" => "whois.nic.br", - "bt" => "whois.netnames.net", - "by" => "whois.ripe.net", - "bz" => "whois.belizenic.bz", - "cd" => "whois.nic.cd", - "ck" => "whois.nic.ck", - "cl" => "nic.cl", - "coop" => "whois.nic.coop", - "cx" => "whois.nic.cx", - "cy" => "whois.ripe.net", - "cz" => "whois.nic.cz", - "dk" => "whois.dk-hostmaster.dk", - "dm" => "whois.nic.cx", - "dz" => "whois.ripe.net", - "ee" => "whois.eenet.ee", - "eg" => "whois.ripe.net", - "es" => "whois.ripe.net", - "fi" => "whois.ficora.fi", - "fo" => "whois.ripe.net", - "gb" => "whois.ripe.net", - "ge" => "whois.ripe.net", - "gl" => "whois.ripe.net", - "gm" => "whois.ripe.net", - "gov" => "whois.nic.gov", - "gr" => "whois.ripe.net", - "gs" => "whois.adamsnames.tc", - "hm" => "whois.registry.hm", - "hn" => "whois2.afilias-grs.net", - "hr" => "whois.ripe.net", - "hu" => "whois.ripe.net", - "il" => "whois.isoc.org.il", - "int" => "whois.isi.edu", - "iq" => "vrx.net", - "ir" => "whois.nic.ir", - "is" => "whois.isnic.is", - "je" => "whois.je", - "jp" => "whois.jprs.jp", - "kg" => "whois.domain.kg", - "kr" => "whois.nic.or.kr", - "la" => "whois2.afilias-grs.net", - "lt" => "whois.domreg.lt", - "lu" => "whois.restena.lu", - "lv" => "whois.nic.lv", - "ly" => "whois.lydomains.com", - "ma" => "whois.iam.net.ma", - "mc" => "whois.ripe.net", - "md" => "whois.nic.md", - "mil" => "whois.nic.mil", - "mk" => "whois.ripe.net", - "ms" => "whois.nic.ms", - "mt" => "whois.ripe.net", - "mu" => "whois.nic.mu", - "my" => "whois.mynic.net.my", - "nf" => "whois.nic.cx", - "pl" => "whois.dns.pl", - "pr" => "whois.nic.pr", - "pt" => "whois.dns.pt", - "sa" => "saudinic.net.sa", - "sb" => "whois.nic.net.sb", - "sg" => "whois.nic.net.sg", - "sh" => "whois.nic.sh", - "si" => "whois.arnes.si", - "sk" => "whois.sk-nic.sk", - "sm" => "whois.ripe.net", - "st" => "whois.nic.st", - "su" => "whois.ripn.net", - "tc" => "whois.adamsnames.tc", - "tf" => "whois.nic.tf", - "th" => "whois.thnic.net", - "tj" => "whois.nic.tj", - "tk" => "whois.nic.tk", - "tl" => "whois.domains.tl", - "tm" => "whois.nic.tm", - "tn" => "whois.ripe.net", - "to" => "whois.tonic.to", - "tp" => "whois.domains.tl", - "tr" => "whois.nic.tr", - "ua" => "whois.ripe.net", - "uy" => "nic.uy", - "uz" => "whois.cctld.uz", - "va" => "whois.ripe.net", - "vc" => "whois2.afilias-grs.net", - "ve" => "whois.nic.ve", - "vg" => "whois.adamsnames.tc", - "yu" => "whois.ripe.net" +class whoisQuery { // Whois查询 + private function whois($content, $host = '') { // 执行Whois查询 + $cmd = $GLOBALS['env']['WHOIS_TOOL'] . ' ' . $content; + if ($host != '') { + $cmd .= ' -h ' . $host; + } + return shell_exec($cmd); + } + + private function formatParam($param) { // 格式化输入参数 + if (strtoupper(substr($param, 0, 2)) === 'AS') { + $asNum = substr($param, 2 - strlen($param)); + if (is_numeric($asNum)) { return 'AS' . $asNum; } // AS + 纯数字 + } + if (filter_var($param, FILTER_VALIDATE_IP)) { // IP地址 + if(filter_var($param, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { // IPv6地址 + $param = (new DNS)->zipIPv6($param); // 格式化IPv6地址 + } + return $param; // IPv4 / IPv6 + } + $info = (new Domain)->analyse($param); + if (isset($info['site'])) { // 请求参数识别到有效域名 + return $info['site']; + } + return null; + } + + private function getWhoisInfo($param) { // 发起whois查询 输入 AS+编号 / IP地址 / 网址 + $notFound = array( + 'No whois server is known for this kind of object.', + 'Unknown AS number or IP network. Please upgrade this program.' ); - if (!isset($servers[$tld])){ - die('Error: No matching nic server found!'); + if (strpos($param, 'AS') === 0 || filter_var($param, FILTER_VALIDATE_IP)) { // 请求内容为 AS编号 / IP地址 + $content = $this->whois($param); + foreach ($notFound as $msg) { // 匹配错误信息 + if (trim($content) === $msg) { + $content = $this->whois($param, 'whois.iana.org'); // 手动查询IANA服务器 + } + } + return array( + 'param' => $param, + 'content' => $content + ); } - $server = $servers[$tld]; - $output = ''; - if ($conn = fsockopen ($server, 43)) { - fputs($conn, $domain."\r\n"); - while(!feof($conn)) { - $output .= fgets($conn, 128); + $content = $this->whois($param); // 请求内容为域名 + if (trim($content) === 'No whois server is known for this kind of object.') { // 无内置whois服务器地址 + $domain = explode('.', $param); + $tld = '.' . $domain[count($domain) - 1]; // 获取网址顶级域名 + $whoisServer = (new Domain)->getWhoisServer($tld); // 获取对应Whois服务器 + if ($whoisServer == null) { + return array( + 'param' => $domain, + 'content' => 'TLD currently has no whois server' // 顶级域无Whois服务器 + ); } - fclose($conn); - } else { - die('Error: Could not connect to ' . $server . '!'); + $content = $this->whois($param, $whoisServer); // 手动向对应服务器查询 } - return $output; + return array( + 'param' => $domain, + 'content' => $content + ); } + public function whoisInfo($param) { // Whois查询接口 带缓存 + $param = $this->formatParam($param); + if ($param == '') { return null; } // 输入错误 + // TODO: redis cache + $info = $this->getWhoisInfo($param); // 发起查询 + return $info; + } +} + +class whoisQueryEntry { public function query($rawParam) { - $content = $this->getWhois($rawParam); + // TODO: help message / enshort whois info / splite long message + $content = (new whoisQuery)->whoisInfo($rawParam)['content']; tgApi::sendMessage(array( 'text' => $content, 'disable_web_page_preview' => 'true' // 不显示页面预览