NetworkDetection.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <?php
  2. namespace App\Utils;
  3. use Http;
  4. use Log;
  5. class NetworkDetection
  6. {
  7. public function ping(string $ip): ?string
  8. { // 用外部API进行Ping检测. TODO: 无权威外部API,功能缺失
  9. $ret = null;
  10. $source = 0;
  11. while ($ret === null && $source <= 2) { // 依次尝试接口
  12. $ret = match ($source) {
  13. 0 => $this->oiowebPing($ip),
  14. 1 => $this->xiaoapiPing($ip),
  15. 2 => $this->yum6Ping($ip),
  16. };
  17. $source++;
  18. }
  19. return $ret;
  20. }
  21. private function oiowebPing(string $ip)
  22. {
  23. $msg = null;
  24. foreach ([1, 6, 14] as $line) {
  25. $url = "https://api.oioweb.cn/api/hostping.php?host=$ip&node=$line"; // https://api.iiwl.cc/api/ping.php?host=
  26. $response = Http::timeout(20)->get($url);
  27. // 发送成功
  28. if ($response->ok()) {
  29. $message = $response->json();
  30. if ($message && $message['code']) {
  31. $msg .= "{$message['node']}:{$message['data']['Time']}<br>";
  32. }
  33. } else {
  34. return false;
  35. }
  36. }
  37. if ($msg) {
  38. return $msg;
  39. }
  40. Log::warning('【PING】检测'.$ip.'时,api.oioweb.cn无结果');
  41. // 发送错误
  42. return false;
  43. }
  44. private function xiaoapiPing(string $ip)
  45. { // 开发依据 https://xiaoapi.cn/?action=doc&id=3
  46. $msg = null;
  47. $response = Http::timeout(15)->get("https://xiaoapi.cn/API/sping.php?url=$ip");
  48. // 发送成功
  49. if ($response->ok()) {
  50. return $response->body();
  51. }
  52. Log::warning("【PING】检测{$ip}时,xiaoapi.cn无结果");
  53. // 发送错误
  54. return false;
  55. }
  56. private function yum6Ping(string $ip)
  57. { // 来源 https://api.yum6.cn/ping.php?host=api.yum6.cn
  58. $url = "https://api.yum6.cn/ping.php?host=$ip";
  59. $response = Http::timeout(20)->get($url);
  60. // 发送成功
  61. if ($response->ok()) {
  62. $msg = $response->json();
  63. if ($msg && $msg['state'] === '1000') {
  64. return "<h4>{$msg['ip']}</h4>线路【{$msg['node']}】<br> 最小值:{$msg['ping_time_min']}<br> 平均值:{$msg['ping_time_avg']}<br> 最大值:{$msg['ping_time_max']}";
  65. }
  66. }
  67. Log::warning('【PING】检测'.$ip.'时,api.yum6.cn无结果');
  68. return false; // 发送错误
  69. }
  70. public function networkStatus(string $ip, int $port): ?array
  71. {
  72. $status = $this->networkCheck($ip, $port);
  73. if ($status) {
  74. $ret = [];
  75. foreach (['icmp', 'tcp'] as $protocol) {
  76. if ($status['in'][$protocol] && $status['out'][$protocol]) {
  77. $check = 1; // 正常
  78. }
  79. if ($status['in'][$protocol] && ! $status['out'][$protocol]) {
  80. $check = 2; // 国外访问异常
  81. }
  82. if (! $status['in'][$protocol] && $status['out'][$protocol]) {
  83. $check = 3; // 被墙
  84. }
  85. $ret[$protocol] = $check ?? 4; // 服务器宕机
  86. }
  87. return $ret;
  88. }
  89. return null;
  90. }
  91. public function networkCheck(string $ip, int $port): ?array
  92. { // 通过众多API进行节点阻断检测.
  93. $ret = null;
  94. $source = 1;
  95. while ($ret === null && $source <= 8) { // 依次尝试接口
  96. $ret = match ($source) {
  97. 1 => $this->toolsdaquan($ip, $port),
  98. 2 => $this->gd($ip, $port),
  99. 3 => $this->vps234($ip),
  100. 4 => $this->flyzy2005($ip, $port),
  101. 5 => $this->idcoffer($ip, $port),
  102. 6 => $this->ip112($ip, $port),
  103. 7 => $this->upx8($ip, $port),
  104. 8 => $this->vps1352($ip, $port),
  105. };
  106. $source++;
  107. }
  108. return $ret;
  109. }
  110. private function toolsdaquan(string $ip, int $port): ?array
  111. { // 开发依据: https://www.toolsdaquan.com/ipcheck/
  112. $response_inner = Http::timeout(15)->withHeaders(['Referer' => 'https://www.toolsdaquan.com/ipcheck/'])->get("https://www.toolsdaquan.com/toolapi/public/ipchecking/$ip/$port");
  113. $response_outer = Http::timeout(15)->withHeaders(['Referer' => 'https://www.toolsdaquan.com/ipcheck/'])->get("https://www.toolsdaquan.com/toolapi/public/ipchecking2/$ip/$port");
  114. if ($response_inner->ok() && $response_outer->ok()) {
  115. return $this->common_detection($response_inner->json(), $response_outer->json(), $ip);
  116. }
  117. return null;
  118. }
  119. private function common_detection(array $inner, array $outer, string $ip): ?array
  120. {
  121. if (empty($inner) || empty($outer)) {
  122. Log::warning("【阻断检测】检测{$ip}时,接口返回异常");
  123. return null;
  124. }
  125. return [
  126. 'in' => [
  127. 'icmp' => $inner['icmp'] === 'success',
  128. 'tcp' => $inner['tcp'] === 'success',
  129. ],
  130. 'out' => [
  131. 'icmp' => $outer['outside_icmp'] === 'success',
  132. 'tcp' => $outer['outside_tcp'] === 'success',
  133. ],
  134. ];
  135. }
  136. private function gd(string $ip, int $port): ?array
  137. { // 开发依据: https://ping.gd/
  138. $response = Http::timeout(20)->get("https://ping.gd/api/ip-test/$ip:$port");
  139. if ($response->ok()) {
  140. $data = $response->json();
  141. if ($data) {
  142. return [
  143. 'in' => [
  144. 'icmp' => $data[0]['result']['ping_alive'],
  145. 'tcp' => $data[0]['result']['telnet_alive'],
  146. ],
  147. 'out' => [
  148. 'icmp' => $data[1]['result']['ping_alive'],
  149. 'tcp' => $data[1]['result']['telnet_alive'],
  150. ],
  151. ];
  152. }
  153. }
  154. Log::warning("【阻断检测】检测{$ip}时,[ping.gd]接口返回异常");
  155. return null;
  156. }
  157. private function vps234(string $ip): ?array
  158. { // 开发依据: https://www.vps234.com/ipchecker/
  159. $response = Http::withoutVerifying()->timeout(15)->asForm()->post('https://www.vps234.com/ipcheck/getdata/', ['ip' => $ip]);
  160. if ($response->ok()) {
  161. $data = $response->json();
  162. if ($data) {
  163. if ($data['error'] === false && $data['data']['success']) {
  164. $result = $data['data']['data'];
  165. return [
  166. 'in' => [
  167. 'icmp' => $result['innerICMP'],
  168. 'tcp' => $result['innerTCP'],
  169. ],
  170. 'out' => [
  171. 'icmp' => $result['outICMP'],
  172. 'tcp' => $result['outTCP'],
  173. ],
  174. ];
  175. }
  176. Log::warning('【阻断检测】检测'.$ip.'时,[vps234]接口返回'.var_export($data, true));
  177. }
  178. Log::warning("【阻断检测】检测{$ip}时, [vps234]接口返回异常");
  179. }
  180. return null;
  181. }
  182. private function flyzy2005(string $ip, int $port): ?array
  183. { // 开发依据: https://www.flyzy2005.cn/tech/ip-check/
  184. $response_inner = Http::timeout(15)->get("https://mini.flyzy2005.cn/ip_check.php?ip=$ip&port=$port");
  185. $response_outer = Http::timeout(15)->get("https://mini.flyzy2005.cn/ip_check_outside.php?ip=$ip&port=$port");
  186. if ($response_inner->ok() && $response_outer->ok()) {
  187. return $this->common_detection($response_inner->json(), $response_outer->json(), $ip);
  188. }
  189. return null;
  190. }
  191. private function idcoffer(string $ip, int $port): ?array
  192. { // 开发依据: https://www.idcoffer.com/ipcheck
  193. $response_inner = Http::timeout(15)->get("https://api.24kplus.com/ipcheck?host=$ip&port=$port");
  194. $response_outer = Http::timeout(15)->get("https://api.idcoffer.com/ipcheck?host=$ip&port=$port");
  195. if ($response_inner->ok() && $response_outer->ok()) {
  196. $inner = $response_inner->json();
  197. $outer = $response_outer->json();
  198. if ($inner && $outer) {
  199. if ($inner['code'] && $outer['code']) {
  200. return [
  201. 'in' => [
  202. 'icmp' => $inner['data']['ping'],
  203. 'tcp' => $inner['data']['tcp'],
  204. ],
  205. 'out' => [
  206. 'icmp' => $outer['data']['ping'],
  207. 'tcp' => $outer['data']['tcp'],
  208. ],
  209. ];
  210. }
  211. Log::warning('【阻断检测】检测'.$ip.$port.'时,[idcoffer]接口返回'.var_export($inner, true).PHP_EOL.var_export($outer, true));
  212. }
  213. Log::warning("【阻断检测】检测{$ip}时,[idcoffer]接口返回异常");
  214. }
  215. return null;
  216. }
  217. private function ip112(string $ip, int $port = 443): ?array
  218. { // 开发依据: https://ip112.cn/
  219. $response_inner = Http::asForm()->post('https://api.ycwxgzs.com/ipcheck/index.php', ['ip' => $ip, 'port' => $port]);
  220. $response_outer = Http::asForm()->post('https://api.52bwg.com/ipcheck/ipcheck.php', ['ip' => $ip, 'port' => $port]);
  221. if ($response_inner->ok() && $response_outer->ok()) {
  222. $inner = $response_inner->json();
  223. $outer = $response_outer->json();
  224. if ($inner && $outer) {
  225. return [
  226. 'in' => [
  227. 'icmp' => str_contains($inner['icmp'], 'green'),
  228. 'tcp' => str_contains($inner['tcp'], 'green'),
  229. ],
  230. 'out' => [
  231. 'icmp' => str_contains($outer['icmp'], 'green'),
  232. 'tcp' => str_contains($outer['tcp'], 'green'),
  233. ],
  234. ];
  235. }
  236. }
  237. Log::warning("【阻断检测】检测{$ip}时,[ip112]接口返回异常");
  238. return null;
  239. }
  240. private function upx8(string $ip, int $port = 443): ?array
  241. { // 开发依据: https://blog.upx8.com/ipcha.html
  242. $response_inner = Http::asForm()->post('https://ip.upx8.com/check.php', ['ip' => $ip, 'port' => $port]);
  243. $response_outer = Http::asForm()->post('https://ip.7761.cf/check.php', ['ip' => $ip, 'port' => $port]);
  244. if ($response_inner->ok() && $response_outer->ok()) {
  245. $inner = $response_inner->json();
  246. $outer = $response_outer->json();
  247. if ($inner && $outer) {
  248. return [
  249. 'in' => [
  250. 'icmp' => $inner['icmp'] === '正常',
  251. 'tcp' => $inner['tcp'] === '正常',
  252. ],
  253. 'out' => [
  254. 'icmp' => $outer['icmp'] === '正常',
  255. 'tcp' => $outer['tcp'] === '正常',
  256. ],
  257. ];
  258. }
  259. }
  260. Log::warning("【阻断检测】检测{$ip}时,[upx8]接口返回异常");
  261. return null;
  262. }
  263. private function vps1352(string $ip, int $port): ?array
  264. { // 开发依据: https://www.51vps.info/ipcheck.html https://www.vps1352.com/ipcheck.html 有缺陷api,查不了海外做判断 备用
  265. $response = Http::asForm()->withHeaders(['Referer' => 'https://www.51vps.info'])->post('https://www.vps1352.com/check.php', ['ip' => $ip, 'port' => $port]);
  266. if ($response->ok()) {
  267. $data = $response->json();
  268. if ($data) {
  269. return [
  270. 'in' => [
  271. 'icmp' => $data['icmp'] === '开放',
  272. 'tcp' => $data['tcp'] === '开放',
  273. ],
  274. 'out' => [
  275. 'icmp' => true,
  276. 'tcp' => true,
  277. ],
  278. ];
  279. }
  280. }
  281. Log::warning("【阻断检测】检测{$ip}时, [vps1352.com]接口返回异常");
  282. return null;
  283. }
  284. }