Quellcode durchsuchen

添加3套节点阻断后备检测方案

原有单一检测api最近一直不稳定,新功能添加检测冗余
兔姬桑 vor 4 Jahren
Ursprung
Commit
a20f077566

+ 178 - 39
app/Components/NetworkDetection.php

@@ -2,32 +2,93 @@
 
 namespace App\Components;
 
-use Cache;
 use Http;
 use Log;
 
 class NetworkDetection
 {
     /**
-     * 用api.50network.com进行节点阻断检测.
+     * 用外部API进行Ping检测.
+     *
+     * @param  string  $ip  被检测的IP或者域名
+     *
+     * @return bool|array
+     */
+    public static function ping(string $ip)
+    {
+        $url = 'https://api.oioweb.cn/api/hostping.php?host='.$ip; // https://api.iiwl.cc/api/ping.php?host=
+        $response = Http::timeout(15)->retry(2)->get($url);
+
+        // 发送成功
+        if ($response->ok()) {
+            $message = $response->json();
+            if ($message && $message['code']) {
+                return $message['data'];
+            }
+            // 发送失败
+            Log::warning('【PING】检测'.$ip.'时,返回'.var_export($message, true));
+
+            return false;
+        }
+        Log::warning('【PING】检测'.$ip.'时,接口返回异常访问链接:'.$url);
+
+        // 发送错误
+        return false;
+    }
+
+    /**
+     * 通过众多API进行节点阻断检测.
      *
      * @param  string  $ip  被检测的IP
-     * @param  bool  $type  TRUE 为ICMP,FALSE 为tcp
+     * @param  bool  $is_icmp  TRUE 为ICMP,FALSE 为tcp
      * @param  int|null  $port  检测端口,默认为空
      *
      * @return bool|string
      */
-    public static function networkCheck(string $ip, bool $type, $port = null)
+    public function networkCheck(string $ip, bool $is_icmp, int $port = null)
     {
-        $cacheKey = 'network_times_'.md5($ip);
-        if (Cache::has($cacheKey)) {
-            Cache::decrement($cacheKey);
+        $round = 0;
+        // 依次尝试接口
+        while (true) {
+            switch ($round) {
+                case 0:
+                    $ret = $this->idcWiki($ip, $is_icmp, $port);
+                    break;
+                case 1:
+                    $ret = $this->flyzy2005($ip, $is_icmp, $port);
+                    break;
+                case 2:
+                    $ret = $this->vps234($ip, $is_icmp);
+                    break;
+                case 3:
+                    $ret = $this->vpsaff($ip, $is_icmp, $port);
+                    break;
+                default:
+                    return false;
+            }
+            if ($ret !== false) {
+                return $ret;
+            }
+            $round++;
+        }
+    }
+
+    private function idcWiki(string $ip, bool $is_icmp, int $port = null)
+    {
+        if ($is_icmp) {
+            $type_string = 'icmp/';
+            $checkName = 'ICMP';
         } else {
-            Cache::put($cacheKey, 2, Day); // 24小时
+            $type_string = 'tcp_ack/';
+            $checkName = 'TCP';
+        }
+        if ($port) {
+            $port = '/'.$port;
+            $type_string = 'tcp_port/';
         }
-        $url = 'https://api.50network.com/china-firewall/check/ip/'.($type ? 'icmp/' : ($port ? 'tcp_port/' : 'tcp_ack/')).$ip.($port ? '/'.$port : '');
 
-        $checkName = $type ? 'ICMP' : 'TCP';
+        $url = "https://api.50network.com/china-firewall/check/ip/{$type_string}{$ip}{$port}";
+
         $response = Http::timeout(15)->get($url);
 
         if ($response->ok()) {
@@ -39,17 +100,6 @@ class NetworkDetection
             }
 
             if (! $message['success']) {
-                if ($message['error'] === 'execute timeout (3s)') {
-                    sleep(10);
-                    if (Cache::get($cacheKey) < 0) {
-                        Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,重复请求后无结果,最后返回'.$message['error']);
-
-                        return false;
-                    }
-
-                    return self::networkCheck($ip, $type, $port);
-                }
-
                 Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,返回'.var_export($message, true));
 
                 return false;
@@ -73,32 +123,121 @@ class NetworkDetection
         return false;
     }
 
-    /**
-     * 用外部API进行Ping检测.
-     *
-     * @param  string  $ip  被检测的IP或者域名
-     *
-     * @return bool|array
-     */
-    public static function ping(string $ip)
+    private function flyzy2005(string $ip, bool $is_icmp, int $port = null)
     {
-        $url = 'https://api.oioweb.cn/api/hostping.php?host='.$ip; // https://api.iiwl.cc/api/ping.php?host=
-        $response = Http::timeout(15)->retry(2)->get($url);
+        $cn = "https://mini.flyzy2005.cn/ip_check.php?ip={$ip}&port={$port}";
+        $us = "https://mini.flyzy2005.cn/ip_check_outside.php?ip={$ip}&port={$port}";
 
-        // 发送成功
+        $checkName = $is_icmp ? 'icmp' : 'tcp';
+
+        $response_cn = Http::timeout(15)->get($cn);
+        $response_us = Http::timeout(15)->get($us);
+
+        if ($response_cn->ok() && $response_us->ok()) {
+            $cn = $response_cn->json();
+            $us = $response_us->json();
+            if (! $cn || ! $us) {
+                Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
+
+                return false;
+            }
+
+            if ($cn[$checkName] === 'success' && $us['outside_'.$checkName] === 'success') {
+                return '通讯正常'; // 正常
+            }
+
+            if ($cn[$checkName] === 'success' && $us['outside_'.$checkName] !== 'success') {
+                return '海外阻断'; // 国外访问异常
+            }
+
+            if ($cn[$checkName] !== 'success' && $us['outside_'.$checkName] === 'success') {
+                return '国内阻断'; // 被墙
+            }
+
+            return '机器宕机'; // 服务器宕机
+        }
+
+        return false;
+    }
+
+    private function vps234(string $ip, bool $is_icmp)
+    {
+        $url = 'https://www.vps234.com/ipcheck/getdata/';
+
+        $checkName = $is_icmp ? 'ICMP' : 'TCP';
+
+        $response = Http::timeout(15)->withoutVerifying()->asForm()->post($url, ['ip' => $ip]);
         if ($response->ok()) {
             $message = $response->json();
-            if ($message && $message['code']) {
-                return $message['data'];
+            if (! $message) {
+                Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,接口返回异常访问链接:'.$url);
+
+                return false;
             }
-            // 发送失败
-            Log::warning('【PING】检测'.$ip.'时,返回'.var_export($message, true));
 
-            return false;
+            if (! $message['data']['success']) {
+                Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,返回'.var_export($message, true));
+
+                return false;
+            }
+
+            if ($message['data']['data']['inner'.$checkName] && $message['data']['data']['out'.$checkName]) {
+                return '通讯正常'; // 正常
+            }
+
+            if ($message['data']['data']['inner'.$checkName] && ! $message['data']['data']['out'.$checkName]) {
+                return '海外阻断'; // 国外访问异常
+            }
+
+            if (! $message['data']['data']['inner'.$checkName] && $message['data']['data']['out'.$checkName]) {
+                return '国内阻断'; // 被墙
+            }
+
+            return '机器宕机'; // 服务器宕机
+        }
+
+        return false;
+    }
+
+    private function vpsaff(string $ip, bool $is_icmp, int $port = null)
+    {
+        $cn = "https://api.24kplus.com/ipcheck?host={$ip}&port={$port}";
+        $us = "https://api.vpsaff.net/ipcheck?host={$ip}&port={$port}";
+        $checkName = $is_icmp ? 'ping' : 'tcp';
+
+        $response_cn = Http::timeout(15)->get($cn);
+        $response_us = Http::timeout(15)->get($us);
+
+        if ($response_cn->ok() && $response_us->ok()) {
+            $cn = $response_cn->json();
+            $us = $response_us->json();
+            if (! $cn || ! $us) {
+                Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
+
+                return false;
+            }
+
+            if (! $cn['code'] || ! $us['code']) {
+                Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,返回'.var_export($cn, true).var_export($us, true));
+
+                return false;
+            }
+
+            if ($cn['data'][$checkName] && $us['data'][$checkName]) {
+                return '通讯正常'; // 正常
+            }
+
+            if ($cn['data'][$checkName] && ! $us['data'][$checkName]) {
+                return '海外阻断'; // 国外访问异常
+            }
+
+            if (! $cn['data'][$checkName] && $us['data'][$checkName]) {
+                return '国内阻断'; // 被墙
+            }
+
+            return '机器宕机'; // 服务器宕机
         }
-        Log::warning('【PING】检测'.$ip.'时,接口返回异常访问链接:'.$url);
 
-        // 发送错误
         return false;
     }
 }

+ 2 - 2
app/Console/Commands/NodeBlockedDetection.php

@@ -59,7 +59,7 @@ class NodeBlockedDetection extends Command
                 }
             }
             if ($node->detection_type !== 1) {
-                $icmpCheck = NetworkDetection::networkCheck($node->ip, true);
+                $icmpCheck = (new NetworkDetection)->networkCheck($node->ip, true);
                 if ($icmpCheck !== false && $icmpCheck !== '通讯正常') {
                     $message .= '| '.$node->name.' | ICMP | '.$icmpCheck." |\r\n";
                     $sendText = true;
@@ -67,7 +67,7 @@ class NodeBlockedDetection extends Command
                 }
             }
             if ($node->detection_type !== 2) {
-                $tcpCheck = NetworkDetection::networkCheck($node->ip, false, $node->single ? $node->port : null);
+                $tcpCheck = (new NetworkDetection)->networkCheck($node->ip, false, $node->single ? $node->port : 22);
                 if ($tcpCheck !== false && $tcpCheck !== '通讯正常') {
                     $message .= '| '.$node->name.' | TCP | '.$tcpCheck." |\r\n";
                     $sendText = true;

+ 2 - 2
app/Http/Controllers/Admin/NodeController.php

@@ -157,8 +157,8 @@ class NodeController extends Controller
                 return Response::json(['status' => 'fail', 'title' => 'IP获取错误', 'message' => $node->name.'IP获取失败']);
             }
         }
-        $data[0] = NetworkDetection::networkCheck($node->ip, true); //ICMP
-        $data[1] = NetworkDetection::networkCheck($node->ip, false, $node->single ? $node->port : null); //TCP
+        $data[0] = (new NetworkDetection)->networkCheck($node->ip, true); //ICMP
+        $data[1] = (new NetworkDetection)->networkCheck($node->ip, false, $node->single ? $node->port : 22); //TCP
 
         return Response::json(['status' => 'success', 'title' => '['.$node->name.']阻断信息', 'message' => $data]);
     }