From 5a72e26a7be2c51a46c4bc6f6880da3ad2b720cf Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Fri, 20 Aug 2021 22:30:13 +0800 Subject: [PATCH] refactor: new IP info model --- .env.example | 10 +- functions/Curl.php | 3 + functions/DNS.php | 72 ++++++++ functions/{ExtractDomain.php => Domain.php} | 7 + main.php | 3 +- models/ipInfo.php | 176 ++++++++------------ models/tgDC.php | 6 +- 7 files changed, 161 insertions(+), 116 deletions(-) create mode 100644 functions/DNS.php rename functions/{ExtractDomain.php => Domain.php} (89%) diff --git a/.env.example b/.env.example index 06bb188..ad9a482 100644 --- a/.env.example +++ b/.env.example @@ -11,16 +11,16 @@ REDIS_PORT=6379 REDIS_PASSWD= REDIS_PREFIX=tgbot -# ChinaZ API -ICP_KEY= -ICP_API=https://apidatav2.chinaz.com/single/icp - # IP Info -ECHOIP_API=https://api.343.re/ip/ +ECHOIP_HOST=ip.343.re # KMS Check KMS_API=https://kms.343.re/ +# ChinaZ API +ICP_KEY= +ICP_API=https://apidatav2.chinaz.com/single/icp + # CFOP Pic CFOP_GAN=BQACAgUAAxkBAAIBtGEOLnr4Q6D4Z_80bgfXq5xsZMeWAAKtAwACWy55VOU-SGKqc7aMIAQ CFOP_MFG=BQACAgUAAxkBAAIB3WEOVHKeYrrGhFo-GffB0W-tQRKlAALQAwACWy55VGny8ArGMkfoIAQ diff --git a/functions/Curl.php b/functions/Curl.php index d566c61..c6411f8 100644 --- a/functions/Curl.php +++ b/functions/Curl.php @@ -1,11 +1,14 @@ ua); $content = curl_exec($curl); curl_close($curl); return $content; diff --git a/functions/DNS.php b/functions/DNS.php new file mode 100644 index 0000000..7aa71f7 --- /dev/null +++ b/functions/DNS.php @@ -0,0 +1,72 @@ +ip2long6($record['ipv6']); + } + sort($ipAddr); // 解析结果排序 + foreach ($ipAddr as &$ip) { + $ip = $this->long2ip6($ip); + } + return $ipAddr; + } + + public function resolveIP($domain) { // DNS解析IP记录 A/AAAA + $ipAddr = array(); + $ipv4 = $this->resolveA($domain); + foreach ($ipv4 as $ip) { + $ipAddr[] = $ip; + } + $ipv6 = $this->resolveAAAA($domain); + foreach ($ipv6 as $ip) { + $ipAddr[] = $ip; + } + return $ipAddr; + } + + private function ip2long6($ipv6) { // 压缩IPv6地址为long + $ip_n = inet_pton($ipv6); + $bits = 15; + while ($bits >= 0) { + $bin = sprintf("%08b", (ord($ip_n[$bits]))); + $ipv6long = $bin.$ipv6long; + $bits--; + } + return gmp_strval(gmp_init($ipv6long, 2), 10); + } + + private function long2ip6($ipv6long) { // 解压long为IPv6地址 + $bin = gmp_strval(gmp_init($ipv6long, 10), 2); + if (strlen($bin) < 128) { + $pad = 128 - strlen($bin); + for ($i = 1; $i <= $pad; $i++) { + $bin = '0' . $bin; + } + } + $bits = 0; + while ($bits <= 7) { + $bin_part = substr($bin, ($bits * 16), 16); + $ipv6 .= dechex(bindec($bin_part)) . ':'; + $bits++; + } + return inet_ntop(inet_pton(substr($ipv6, 0, -1))); + } +} + +?> diff --git a/functions/ExtractDomain.php b/functions/Domain.php similarity index 89% rename from functions/ExtractDomain.php rename to functions/Domain.php index cbcacae..be4398e 100644 --- a/functions/ExtractDomain.php +++ b/functions/Domain.php @@ -1,5 +1,12 @@ apiPath = $env['ECHOIP_API']; + $this->apiPath = 'https://' . $GLOBALS['env']['ECHOIP_HOST'] . '/info/'; } private function changeCoor($num) { // 转为时分秒格式 @@ -27,83 +26,32 @@ class ipInfo { return $str; } - public function getInfo($ip) { - if (!filter_var($ip, FILTER_VALIDATE_IP)) { // IP地址不合法 - return array( - 'status' => 'error', - 'message' => 'Illegal IP Address' - ); - } - $redis = new redisCache('ip'); + private function getIpInfo($ip) { // 向上游查询IP信息 + $content = (new Curl)->get($this->apiPath . $ip); + $info = json_decode($content, true); + if ($info['status'] !== 'T') { return null; } + unset($info['status']); + return $info + array( + 'locCoor' => $this->coorFormat($info['loc']) // 经纬度格式 + ); + } + + public function getInfo($ip) { // 查询IP信息 错误返回null + $redis = new RedisCache('ip'); $info = $redis->getData($ip); // 查询缓存数据 if (!$info) { // 缓存未命中 - $info = json_decode(file_get_contents($this->apiPath . $ip), true); - if ($info['status'] !== 'T') { // 上游接口错误 - return array( - 'status' => 'error', - 'message' => 'Server Error' - ); - } - unset($info['status']); - if ($info['loc'] != NULL) { - $info['locCoor'] = $this->coorFormat($info['loc']); // 转换为经纬度格式 - } - $redis->setData($ip, json_encode($info), 1800); // 缓存30min + $info = $this->getIpInfo($ip); + if ($info === null) { return null; } // 服务错误 返回null + $redis->setData($ip, json_encode($info), 43200); // 缓存12h } else { // 缓存命中 $info = json_decode($info, true); // 使用缓存数据 } - return array( - 'status' => 'ok', - 'data' => json_encode($info) // 返回查询结果 - ); + return $info; // 查询成功 返回结果 } } -class ipInfoEntry { - private function isDomain($domain) { // 检测是否为域名 - preg_match('/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/', $domain, $match); - return (count($match) != 0); - } - - private function dnsResolveIPv4($domain) { // DNS解析A记录 - $ipAddr = array(); - $rs = dns_get_record(strtolower($domain), DNS_A); - foreach ($rs as $record) { - $ipAddr[] = $record['ip']; - } - return $ipAddr; - } - - private function dnsResolveIPv6($domain) { // DNS解析AAAA记录 - $ipAddr = array(); - $rs = dns_get_record(strtolower($domain), DNS_AAAA); - foreach ($rs as $record) { - $ipAddr[] = $record['ipv6']; - } - return $ipAddr; - } - - private function dnsResolve($domain) { // DNS解析IP记录 - $ipAddr = array(); - $ipv4 = $this->dnsResolveIPv4($domain); - foreach ($ipv4 as $ip) { - $ipAddr[] = $ip; - } - $ipv6 = $this->dnsResolveIPv6($domain); - foreach ($ipv6 as $ip) { - $ipAddr[] = $ip; - } - return $ipAddr; - } - - private function getInfo($ip) { - $content = (new ipInfo)->getInfo($ip); // 发起查询 - if ($content['status'] !== 'ok') { - return array( - 'text' => $content['message'] // 返回错误信息 - ); - } - $info = json_decode($content['data'], true); +class ipInfoEntry { // IP信息查询入口 + private function genMessage($info) { // 生成返回信息 $msg = 'IP: ' . $info['ip'] . '' . PHP_EOL; if ($info['as'] != NULL) { $msg .= 'AS: '; @@ -122,43 +70,37 @@ class ipInfoEntry { if ($info['scope'] != NULL) { $msg .= 'Scope: ' . $info['scope'] . '' . PHP_EOL; } if ($info['detail'] != NULL) { $msg .= 'Detail: ' . $info['detail'] . PHP_EOL; } return array( + 'text' => $msg, 'parse_mode' => 'HTML', // HTML格式输出 'disable_web_page_preview' => 'true', // 不显示页面预览 - 'text' => $msg, - 'reply_markup' => json_encode(array( // 显示按钮 - 'inline_keyboard' => array([[ - 'text' => 'View on echoIP', - 'url' => 'https://ip.dnomd343.top/?ip=' . $ip - ]]) - )) + 'reply_markup' => $this->genButton('View on echoIP', $info['ip']) // 显示按钮 ); } - public function query($rawParam) { // ipInfo查询入口 - if ($rawParam == '' || $rawParam === 'help') { // 显示使用说明 - tgApi::sendMessage(array( - 'parse_mode' => 'Markdown', - 'text' => '*Usage:* `/ip IPv4/IPv6/Domain`', - 'reply_markup' => json_encode(array( // 显示echoIP按钮 - 'inline_keyboard' => array([[ - 'text' => 'Get my IP address', - 'url' => 'https://ip.dnomd343.top/' - ]]) - )) - )); - return; - } - if (filter_var($rawParam, FILTER_VALIDATE_IP)) { // 参数为IP地址 - tgApi::sendMessage($this->getInfo($rawParam)); // 发起查询 - return; - } - if (!$this->isDomain($rawParam)) { - tgApi::sendText('Illegal Request'); // 非法请求 + private function genButton($text, $ip = '') { // 生成ehcoIP页面链接按钮 默认为主页 + $url = 'https://' . $GLOBALS['env']['ECHOIP_HOST'] . '/'; + if ($ip !== '') { $url .= '?ip=' . $ip; } + return json_encode(array( + 'inline_keyboard' => array([[ // echoIP按钮 + 'text' => $text, + 'url' => $url + ]]) + )); + } + + private function sendInfo($ip) { // 查询并发送IP信息 + $info = (new ipInfo)->getInfo($ip); + if ($info === null) { + tgApi::sendText('Server error'); // 上游查询错误 return; } - $ips = $this->dnsResolve($rawParam); + tgApi::sendMessage($this->genMessage($info)); + } + + private function sendDomainInfo($domain) { // 查询并发送域名解析结果 + $ips = (new DNS)->resolveIP($domain); if (count($ips) == 0) { // 解析不到IP记录 - tgApi::sendMarkdown('Nothing found of `' . $rawParam . '`'); + tgApi::sendMarkdown('Nothing found of `' . $domain . '`'); return; } foreach ($ips as $ip) { @@ -170,27 +112,47 @@ class ipInfoEntry { if (count($ips) >= 2) { $buttons[] = array([ // 两个及以上的IP 添加显示全部的按钮 'text' => 'Get all detail', - 'callback_data' => '/ip ' . $rawParam + 'callback_data' => '/ip ' . $domain ]); } tgApi::sendMessage(array( 'parse_mode' => 'Markdown', - 'text' => 'DNS resolve of `' . $rawParam . '`', - 'reply_markup' => json_encode(array( // 显示IP列表按钮 + 'text' => 'DNS resolve of `' . $domain . '`', + 'reply_markup' => json_encode(array( // IP列表按钮 'inline_keyboard' => $buttons )) )); } + private function sendHelp() { // 发送使用说明 + $helpMessage = array( + 'parse_mode' => 'Markdown', + 'text' => '*Usage:* `/ip IPv4/IPv6/Domain`', + 'reply_markup' => $this->genButton('Get my IP address') // echoIP主页链接 + ); + tgApi::sendMessage($helpMessage); + } + + public function query($rawParam) { // ipInfo查询入口 + if ($rawParam == '' || $rawParam === 'help') { + $this->sendHelp(); // 显示使用说明 + } else if (filter_var($rawParam, FILTER_VALIDATE_IP)) { // 参数为IP地址 + $this->sendInfo($rawParam); // 查询并发送IP信息 + } else if ((new Domain)->isDomain($rawParam)) { // 参数为域名 + $this->sendDomainInfo($rawParam); // 查询并发送域名信息 + } else { + tgApi::sendText('Illegal Request'); // 非法请求 + } + } + public function callback($rawParam) { // ipInfo回调入口 if (filter_var($rawParam, FILTER_VALIDATE_IP)) { // 参数为IP地址 $this->query($rawParam); } else { // 参数为域名 - global $tgEnv; tgApi::deleteMessage(array( - 'message_id' => $tgEnv['messageId'] + 'message_id' => $GLOBALS['tgEnv']['messageId'] )); - $ips = $this->dnsResolve($rawParam); + $ips = (new DNS)->resolveIP($rawParam); foreach ($ips as $ip) { $this->query($ip); // 逐个输出 } diff --git a/models/tgDC.php b/models/tgDC.php index 25154fb..c58469f 100644 --- a/models/tgDC.php +++ b/models/tgDC.php @@ -83,7 +83,7 @@ class tgDCEntry { // DC查询入口 return true; } - private function showHelp() { // 显示帮助信息 + private function sendHelp() { // 显示帮助信息 $message = tgApi::sendMarkdown('*Usage:* `/dc username`'); $message = json_decode($message, true); return $message['result']['message_id']; // 返回消息ID @@ -133,11 +133,11 @@ class tgDCEntry { // DC查询入口 public function query($rawParam) { // tgDC查询入口 global $tgEnv; - if ($rawParam === 'help') { $this->showHelp(); } // 显示使用说明 + if ($rawParam === 'help') { $this->sendHelp(); } // 显示使用说明 if ($rawParam == '') { $rawParam = $tgEnv['userAccount']; // 空指令时查询对方信息 if (!$tgEnv['isGroup']) { - $messageId = $this->showHelp(); // 非群组发送使用说明 + $messageId = $this->sendHelp(); // 非群组发送使用说明 } } if (substr($rawParam, 0, 1) === '@') {