NetworkDetection.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. * @return bool
  12. */
  13. public function ping(string $ip)
  14. {
  15. $round = 1;
  16. // 依次尝试接口
  17. while (true) {
  18. switch ($round) {
  19. case 0:
  20. $ret = $this->oiowebPing($ip);
  21. break;
  22. case 1:
  23. $ret = $this->xiaoapiPing($ip);
  24. break;
  25. case 2:
  26. $ret = $this->yum6Ping($ip);
  27. break;
  28. default:
  29. return false;
  30. }
  31. if ($ret !== false) {
  32. return $ret;
  33. }
  34. $round++;
  35. }
  36. }
  37. private function oiowebPing(string $ip)
  38. {
  39. $msg = null;
  40. foreach ([1, 6, 14] as $line) {
  41. $url = "https://api.oioweb.cn/api/hostping.php?host={$ip}&node={$line}"; // https://api.iiwl.cc/api/ping.php?host=
  42. $response = Http::timeout(20)->get($url);
  43. // 发送成功
  44. if ($response->ok()) {
  45. $message = $response->json();
  46. if ($message && $message['code']) {
  47. $msg .= "{$message['node']}:{$message['data']['Time']}<br>";
  48. }
  49. } else {
  50. return false;
  51. }
  52. }
  53. if ($msg) {
  54. return $msg;
  55. }
  56. Log::warning('【PING】检测'.$ip.'时,api.oioweb.cn无结果');
  57. // 发送错误
  58. return false;
  59. }
  60. private function xiaoapiPing(string $ip)
  61. { // 来源 https://xiaoapi.cn/?action=doc&id=3
  62. $msg = null;
  63. $url = "https://xiaoapi.cn/API/sping.php?url={$ip}";
  64. $response = Http::timeout(20)->get($url);
  65. // 发送成功
  66. if ($response->ok()) {
  67. return $response->body();
  68. }
  69. Log::warning('【PING】检测'.$ip.'时,xiaoapi.cn无结果');
  70. // 发送错误
  71. return false;
  72. }
  73. private function yum6Ping(string $ip)
  74. { // 来源 https://api.yum6.cn/ping.php?host=api.yum6.cn
  75. $url = "https://api.yum6.cn/ping.php?host={$ip}";
  76. $response = Http::timeout(20)->get($url);
  77. // 发送成功
  78. if ($response->ok()) {
  79. $msg = $response->json();
  80. if ($msg && $msg['state'] === '1000') {
  81. return "<h4>{$msg['ip']}</h4>线路【{$msg['node']}】<br> 最小值:{$msg['ping_time_min']}<br> 平均值:{$msg['ping_time_avg']}<br> 最大值:{$msg['ping_time_max']}";
  82. }
  83. }
  84. Log::warning('【PING】检测'.$ip.'时,api.yum6.cn无结果');
  85. // 发送错误
  86. return false;
  87. }
  88. /**
  89. * 通过众多API进行节点阻断检测.
  90. *
  91. * @param string $ip 被检测的IP
  92. * @param bool $is_icmp TRUE 为ICMP,FALSE 为tcp
  93. * @param int|null $port 检测端口,默认为空
  94. * @return bool
  95. */
  96. public function networkCheck(string $ip, bool $is_icmp, int $port = null)
  97. {
  98. $round = 1;
  99. // 依次尝试接口
  100. while (true) {
  101. switch ($round) {
  102. case 0:
  103. $ret = $this->idcWiki($ip, $is_icmp, $port);
  104. break;
  105. case 1:
  106. $ret = $this->flyzy2005($ip, $is_icmp, $port);
  107. break;
  108. case 2:
  109. $ret = $this->vps234($ip, $is_icmp);
  110. break;
  111. case 3:
  112. $ret = $this->idcoffer($ip, $is_icmp, $port);
  113. break;
  114. case 4:
  115. $ret = $this->gd($ip, $is_icmp, $port);
  116. break;
  117. case 5:
  118. $ret = $this->ip112($ip, $is_icmp, $port);
  119. break;
  120. default:
  121. return false;
  122. }
  123. if ($ret !== false) {
  124. return $ret;
  125. }
  126. $round++;
  127. }
  128. }
  129. private function idcWiki(string $ip, bool $is_icmp, int $port = null)
  130. {
  131. if ($is_icmp) {
  132. $type_string = 'icmp/';
  133. $checkName = 'ICMP';
  134. } else {
  135. $type_string = 'tcp_ack/';
  136. $checkName = 'TCP';
  137. }
  138. if ($port) {
  139. $port = '/'.$port;
  140. $type_string = 'tcp_port/';
  141. }
  142. $url = "https://api.50network.com/china-firewall/check/ip/{$type_string}{$ip}{$port}";
  143. $response = Http::timeout(20)->get($url);
  144. if ($response->ok()) {
  145. $message = $response->json();
  146. if (! $message) {
  147. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,接口返回异常访问链接:'.$url);
  148. return false;
  149. }
  150. if (! $message['success']) {
  151. if (isset($message['error']) && $message['error'] === 'execute timeout (3s)') {
  152. return false;
  153. }
  154. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,返回'.var_export($message, true));
  155. return false;
  156. }
  157. if ($message['firewall-enable'] && $message['firewall-disable']) {
  158. return 1; // 正常
  159. }
  160. if ($message['firewall-enable'] && ! $message['firewall-disable']) {
  161. return 2; // 国外访问异常
  162. }
  163. if (! $message['firewall-enable'] && $message['firewall-disable']) {
  164. return 3; // 被墙
  165. }
  166. return 4; // 服务器宕机
  167. }
  168. return false;
  169. }
  170. private function flyzy2005(string $ip, bool $is_icmp, int $port = null)
  171. {
  172. $cn = "https://mini.flyzy2005.cn/ip_check.php?ip={$ip}&port={$port}";
  173. $us = "https://mini.flyzy2005.cn/ip_check_outside.php?ip={$ip}&port={$port}";
  174. $checkName = $is_icmp ? 'icmp' : 'tcp';
  175. $response_cn = Http::timeout(20)->get($cn);
  176. $response_us = Http::timeout(20)->get($us);
  177. if ($response_cn->ok() && $response_us->ok()) {
  178. $cn = $response_cn->json();
  179. $us = $response_us->json();
  180. if (! $cn || ! $us) {
  181. Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
  182. return false;
  183. }
  184. if ($cn[$checkName] === 'success' && $us['outside_'.$checkName] === 'success') {
  185. return 1; // 正常
  186. }
  187. if ($cn[$checkName] === 'success' && $us['outside_'.$checkName] !== 'success') {
  188. return 2; // 国外访问异常
  189. }
  190. if ($cn[$checkName] !== 'success' && $us['outside_'.$checkName] === 'success') {
  191. return 3; // 被墙
  192. }
  193. return 4; // 服务器宕机
  194. }
  195. return false;
  196. }
  197. private function vps234(string $ip, bool $is_icmp)
  198. {
  199. $url = 'https://www.vps234.com/ipcheck/getdata/';
  200. $checkName = $is_icmp ? 'ICMP' : 'TCP';
  201. $response = Http::timeout(20)->withoutVerifying()->asForm()->post($url, ['ip' => $ip]);
  202. if ($response->ok()) {
  203. $message = $response->json();
  204. if (! $message) {
  205. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,接口返回异常访问链接:'.$url);
  206. return false;
  207. }
  208. if (! $message['data']['success']) {
  209. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.'时,返回'.var_export($message, true));
  210. return false;
  211. }
  212. if ($message['data']['data']['inner'.$checkName] && $message['data']['data']['out'.$checkName]) {
  213. return 1; // 正常
  214. }
  215. if ($message['data']['data']['inner'.$checkName] && ! $message['data']['data']['out'.$checkName]) {
  216. return 2; // 国外访问异常
  217. }
  218. if (! $message['data']['data']['inner'.$checkName] && $message['data']['data']['out'.$checkName]) {
  219. return 3; // 被墙
  220. }
  221. return 4; // 服务器宕机
  222. }
  223. return false;
  224. }
  225. private function idcoffer(string $ip, bool $is_icmp, int $port = null)
  226. { // 来源:https://www.idcoffer.com/ipcheck
  227. $cn = "https://api.24kplus.com/ipcheck?host={$ip}&port={$port}";
  228. $us = "https://api.idcoffer.com/ipcheck?host={$ip}&port={$port}";
  229. $checkName = $is_icmp ? 'ping' : 'tcp';
  230. $response_cn = Http::timeout(20)->get($cn);
  231. $response_us = Http::timeout(20)->get($us);
  232. if ($response_cn->ok() && $response_us->ok()) {
  233. $cn = $response_cn->json();
  234. $us = $response_us->json();
  235. if (! $cn || ! $us) {
  236. Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
  237. return false;
  238. }
  239. if (! $cn['code'] || ! $us['code']) {
  240. Log::warning('【'.$checkName.'阻断检测】检测'.$ip.$port.'时,返回'.var_export($cn, true).var_export($us, true));
  241. return false;
  242. }
  243. if ($cn['data'][$checkName] && $us['data'][$checkName]) {
  244. return 1; // 正常
  245. }
  246. if ($cn['data'][$checkName] && ! $us['data'][$checkName]) {
  247. return 2; // 国外访问异常
  248. }
  249. if (! $cn['data'][$checkName] && $us['data'][$checkName]) {
  250. return 3; // 被墙
  251. }
  252. return 4; // 服务器宕机
  253. }
  254. return false;
  255. }
  256. private function gd(string $ip, bool $is_icmp, int $port = 443)
  257. { // 来源:https://ping.gd/
  258. $url = "https://ping.gd/api/ip-test/{$ip}:".($port ?? 443);
  259. $checkName = $is_icmp ? 'ping_alive' : 'telnet_alive';
  260. $response = Http::timeout(20)->get($url);
  261. if ($response->ok()) {
  262. $message = $response->json();
  263. if (! $message) {
  264. Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$url}");
  265. return false;
  266. }
  267. if ($message[0]['result'][$checkName] && $message[1]['result'][$checkName]) {
  268. return 1; // 正常
  269. }
  270. if ($message[0]['result'][$checkName] && ! $message[1]['result'][$checkName]) {
  271. return 2; // 国外访问异常
  272. }
  273. if (! $message[0]['result'][$checkName] && $message[1]['result'][$checkName]) {
  274. return 3; // 被墙
  275. }
  276. return 4; // 服务器宕机
  277. }
  278. return false;
  279. }
  280. private function ip112(string $ip, bool $is_icmp, int $port = 443)
  281. { // 来源:https://ip112.cn/
  282. $cn = 'https://api.zhujiquanzi.com/ipcheck/ipcheck.php';
  283. $us = 'https://api.52bwg.com/ipcheck/ipcheck.php';
  284. $checkName = $is_icmp ? 'icmp' : 'tcp';
  285. $response_cn = Http::asForm()->post($cn, ['ip' => $ip, 'port' => $port]);
  286. $response_us = Http::asForm()->post($us, ['ip' => $ip, 'port' => $port]);
  287. if ($response_cn->ok() && $response_us->ok()) {
  288. $cn = $response_cn->json();
  289. $us = $response_us->json();
  290. if (! $cn || ! $us) {
  291. Log::warning("【{$checkName}阻断检测】检测{$ip}时,接口返回异常访问链接:{$cn} | {$us}");
  292. return false;
  293. }
  294. if (str_contains($cn[$checkName], 'green') && str_contains($us[$checkName], 'green')) {
  295. return 1; // 正常
  296. }
  297. if (str_contains($cn[$checkName], 'green') && ! str_contains($us[$checkName], 'green')) {
  298. return 2; // 国外访问异常
  299. }
  300. if (! str_contains($cn[$checkName], 'green') && str_contains($us[$checkName], 'green')) {
  301. return 3; // 被墙
  302. }
  303. return 4; // 服务器宕机
  304. }
  305. return false;
  306. }
  307. }