NetworkDetection.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. namespace App\Components;
  3. use Http;
  4. use Log;
  5. class NetworkDetection
  6. {
  7. /**
  8. * 用外部API进行Ping检测.
  9. *
  10. * @param string $ip 被检测的IP或者域名
  11. *
  12. * @return bool|array
  13. */
  14. public static function ping(string $ip)
  15. {
  16. $url = 'https://api.oioweb.cn/api/hostping.php?host='.$ip; // https://api.iiwl.cc/api/ping.php?host=
  17. $response = Http::timeout(15)->retry(2)->get($url);
  18. // 发送成功
  19. if ($response->ok()) {
  20. $message = $response->json();
  21. if ($message && $message['code']) {
  22. return $message['data'];
  23. }
  24. // 发送失败
  25. Log::warning('【PING】检测'.$ip.'时,返回'.var_export($message, true));
  26. return false;
  27. }
  28. Log::warning('【PING】检测'.$ip.'时,接口返回异常访问链接:'.$url);
  29. // 发送错误
  30. return false;
  31. }
  32. /**
  33. * 通过众多API进行节点阻断检测.
  34. *
  35. * @param string $ip 被检测的IP
  36. * @param bool $is_icmp TRUE 为ICMP,FALSE 为tcp
  37. * @param int|null $port 检测端口,默认为空
  38. *
  39. * @return bool|string
  40. */
  41. public function networkCheck(string $ip, bool $is_icmp, int $port = null)
  42. {
  43. $round = 0;
  44. // 依次尝试接口
  45. while (true) {
  46. switch ($round) {
  47. case 0:
  48. $ret = $this->idcWiki($ip, $is_icmp, $port);
  49. break;
  50. case 1:
  51. $ret = $this->flyzy2005($ip, $is_icmp, $port);
  52. break;
  53. case 2:
  54. $ret = $this->vps234($ip, $is_icmp);
  55. break;
  56. case 3:
  57. $ret = $this->vpsaff($ip, $is_icmp, $port);
  58. break;
  59. default:
  60. return false;
  61. }
  62. if ($ret !== false) {
  63. return $ret;
  64. }
  65. $round++;
  66. }
  67. }
  68. private function idcWiki(string $ip, bool $is_icmp, int $port = null)
  69. {
  70. if ($is_icmp) {
  71. $type_string = 'icmp/';
  72. $checkName = 'ICMP';
  73. } else {
  74. $type_string = 'tcp_ack/';
  75. $checkName = 'TCP';
  76. }
  77. if ($port) {
  78. $port = '/'.$port;
  79. $type_string = 'tcp_port/';
  80. }
  81. $url = "https://api.50network.com/china-firewall/check/ip/{$type_string}{$ip}{$port}";
  82. $response = Http::timeout(15)->get($url);
  83. if ($response->ok()) {
  84. $message = $response->json();
  85. if (! $message) {
  86. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,接口返回异常访问链接:'.$url);
  87. return false;
  88. }
  89. if (! $message['success']) {
  90. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,返回'.var_export($message, true));
  91. return false;
  92. }
  93. if ($message['firewall-enable'] && $message['firewall-disable']) {
  94. return '通讯正常'; // 正常
  95. }
  96. if ($message['firewall-enable'] && ! $message['firewall-disable']) {
  97. return '海外阻断'; // 国外访问异常
  98. }
  99. if (! $message['firewall-enable'] && $message['firewall-disable']) {
  100. return '国内阻断'; // 被墙
  101. }
  102. return '机器宕机'; // 服务器宕机
  103. }
  104. return false;
  105. }
  106. private function flyzy2005(string $ip, bool $is_icmp, int $port = null)
  107. {
  108. $cn = "https://mini.flyzy2005.cn/ip_check.php?ip={$ip}&port={$port}";
  109. $us = "https://mini.flyzy2005.cn/ip_check_outside.php?ip={$ip}&port={$port}";
  110. $checkName = $is_icmp ? 'icmp' : 'tcp';
  111. $response_cn = Http::timeout(15)->get($cn);
  112. $response_us = Http::timeout(15)->get($us);
  113. if ($response_cn->ok() && $response_us->ok()) {
  114. $cn = $response_cn->json();
  115. $us = $response_us->json();
  116. if (! $cn || ! $us) {
  117. Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
  118. return false;
  119. }
  120. if ($cn[$checkName] === 'success' && $us['outside_'.$checkName] === 'success') {
  121. return '通讯正常'; // 正常
  122. }
  123. if ($cn[$checkName] === 'success' && $us['outside_'.$checkName] !== 'success') {
  124. return '海外阻断'; // 国外访问异常
  125. }
  126. if ($cn[$checkName] !== 'success' && $us['outside_'.$checkName] === 'success') {
  127. return '国内阻断'; // 被墙
  128. }
  129. return '机器宕机'; // 服务器宕机
  130. }
  131. return false;
  132. }
  133. private function vps234(string $ip, bool $is_icmp)
  134. {
  135. $url = 'https://www.vps234.com/ipcheck/getdata/';
  136. $checkName = $is_icmp ? 'ICMP' : 'TCP';
  137. $response = Http::timeout(15)->withoutVerifying()->asForm()->post($url, ['ip' => $ip]);
  138. if ($response->ok()) {
  139. $message = $response->json();
  140. if (! $message) {
  141. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,接口返回异常访问链接:'.$url);
  142. return false;
  143. }
  144. if (! $message['data']['success']) {
  145. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,返回'.var_export($message, true));
  146. return false;
  147. }
  148. if ($message['data']['data']['inner'.$checkName] && $message['data']['data']['out'.$checkName]) {
  149. return '通讯正常'; // 正常
  150. }
  151. if ($message['data']['data']['inner'.$checkName] && ! $message['data']['data']['out'.$checkName]) {
  152. return '海外阻断'; // 国外访问异常
  153. }
  154. if (! $message['data']['data']['inner'.$checkName] && $message['data']['data']['out'.$checkName]) {
  155. return '国内阻断'; // 被墙
  156. }
  157. return '机器宕机'; // 服务器宕机
  158. }
  159. return false;
  160. }
  161. private function vpsaff(string $ip, bool $is_icmp, int $port = null)
  162. {
  163. $cn = "https://api.24kplus.com/ipcheck?host={$ip}&port={$port}";
  164. $us = "https://api.vpsaff.net/ipcheck?host={$ip}&port={$port}";
  165. $checkName = $is_icmp ? 'ping' : 'tcp';
  166. $response_cn = Http::timeout(15)->get($cn);
  167. $response_us = Http::timeout(15)->get($us);
  168. if ($response_cn->ok() && $response_us->ok()) {
  169. $cn = $response_cn->json();
  170. $us = $response_us->json();
  171. if (! $cn || ! $us) {
  172. Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
  173. return false;
  174. }
  175. if (! $cn['code'] || ! $us['code']) {
  176. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,返回'.var_export($cn, true).var_export($us, true));
  177. return false;
  178. }
  179. if ($cn['data'][$checkName] && $us['data'][$checkName]) {
  180. return '通讯正常'; // 正常
  181. }
  182. if ($cn['data'][$checkName] && ! $us['data'][$checkName]) {
  183. return '海外阻断'; // 国外访问异常
  184. }
  185. if (! $cn['data'][$checkName] && $us['data'][$checkName]) {
  186. return '国内阻断'; // 被墙
  187. }
  188. return '机器宕机'; // 服务器宕机
  189. }
  190. return false;
  191. }
  192. }