NetworkDetection.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <?php
  2. namespace App\Utils;
  3. use Exception;
  4. use Http;
  5. use Illuminate\Http\Client\PendingRequest;
  6. use Log;
  7. class NetworkDetection
  8. {
  9. private static PendingRequest $basicRequest;
  10. public function networkStatus(string $ip, int $port): ?array
  11. {
  12. $status = $this->networkCheck($ip, $port);
  13. if ($status) {
  14. $ret = [];
  15. foreach (['icmp', 'tcp'] as $protocol) {
  16. if ($status['in'][$protocol] && $status['out'][$protocol]) {
  17. $check = 1; // 正常
  18. }
  19. if ($status['in'][$protocol] && ! $status['out'][$protocol]) {
  20. $check = 2; // 国外访问异常
  21. }
  22. if (! $status['in'][$protocol] && $status['out'][$protocol]) {
  23. $check = 3; // 被墙
  24. }
  25. $ret[$protocol] = $check ?? 4; // 服务器宕机
  26. }
  27. return $ret;
  28. }
  29. return null;
  30. }
  31. private function networkCheck(string $ip, int $port): ?array
  32. { // 通过众多API进行节点阻断检测.
  33. $checkers = ['toolsdaquan', 'vps234', 'flyzy2005', 'idcoffer', 'ip112', 'upx8', 'rss', 'gd', 'vps1352', 'akile'];
  34. self::$basicRequest = Http::timeout(15)->retry(2)->withOptions(['http_errors' => false])->withoutVerifying()->withUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36');
  35. foreach ($checkers as $checker) {
  36. try {
  37. if (method_exists(self::class, $checker)) {
  38. $result = $this->$checker($ip, $port);
  39. if ($result !== null) {
  40. return $result;
  41. }
  42. }
  43. } catch (Exception $e) {
  44. Log::error("[$checker] 网络阻断测试报错: ".$e->getMessage());
  45. continue;
  46. }
  47. }
  48. return null;
  49. }
  50. private function toolsdaquan(string $ip, int $port): ?array
  51. { // 开发依据: https://www.toolsdaquan.com/ipcheck/
  52. $response_inner = self::$basicRequest->withHeader('Referer', 'https://www.toolsdaquan.com/ipcheck/')->get("https://www.toolsdaquan.com/toolapi/public/ipchecking/$ip/$port");
  53. $response_outer = self::$basicRequest->withHeader('Referer', 'https://www.toolsdaquan.com/ipcheck/')->get("https://www.toolsdaquan.com/toolapi/public/ipchecking2/$ip/$port");
  54. if ($response_inner->ok() && $response_outer->ok()) {
  55. return $this->common_detection($response_inner->json(), $response_outer->json(), $ip);
  56. }
  57. return null;
  58. }
  59. private function common_detection(array $inner, array $outer, string $ip): ?array
  60. {
  61. if (empty($inner) || empty($outer)) {
  62. Log::warning("【阻断检测】检测{$ip}时,接口返回异常");
  63. return null;
  64. }
  65. return [
  66. 'in' => [
  67. 'icmp' => $inner['icmp'] === 'success',
  68. 'tcp' => $inner['tcp'] === 'success',
  69. ],
  70. 'out' => [
  71. 'icmp' => $outer['outside_icmp'] === 'success',
  72. 'tcp' => $outer['outside_tcp'] === 'success',
  73. ],
  74. ];
  75. }
  76. private function akile(string $ip, int $port): ?array
  77. { // 开发依据: https://tools.akile.io/
  78. $response = self::$basicRequest->get("https://tools.akile.io/gping?address=$ip&port=$port");
  79. if ($response->ok()) {
  80. $data = $response->json();
  81. if ($data) {
  82. return [
  83. 'in' => [
  84. 'icmp' => $data['cn_icmp'],
  85. 'tcp' => $data['cn_tcp'],
  86. ],
  87. 'out' => [
  88. 'icmp' => $data['global_icmp'],
  89. 'tcp' => $data['global_tcp'],
  90. ],
  91. ];
  92. }
  93. }
  94. Log::warning("【阻断检测】检测{$ip}时,[akile]接口返回异常");
  95. return null;
  96. }
  97. private function gd(string $ip, int $port): ?array
  98. { // 开发依据: https://ping.gd/
  99. $response = self::$basicRequest->get("https://ping.gd/api/ip-test/$ip:$port");
  100. if ($response->ok()) {
  101. $data = $response->json();
  102. if ($data) {
  103. return [
  104. 'in' => [
  105. 'icmp' => $data[0]['result']['ping_alive'],
  106. 'tcp' => $data[0]['result']['telnet_alive'],
  107. ],
  108. 'out' => [
  109. 'icmp' => $data[1]['result']['ping_alive'],
  110. 'tcp' => $data[1]['result']['telnet_alive'],
  111. ],
  112. ];
  113. }
  114. }
  115. Log::warning("【阻断检测】检测{$ip}时,[ping.gd]接口返回异常");
  116. return null;
  117. }
  118. private function vps234(string $ip): ?array
  119. { // 开发依据: https://www.vps234.com/ipchecker/
  120. $response = self::$basicRequest->asForm()->post('https://www.vps234.com/ipcheck/getdata/', ['ip' => $ip]);
  121. if ($response->ok()) {
  122. $data = $response->json();
  123. if ($data) {
  124. if ($data['error'] === false && $data['data']['success']) {
  125. $result = $data['data']['data'];
  126. return [
  127. 'in' => [
  128. 'icmp' => $result['innerICMP'],
  129. 'tcp' => $result['innerTCP'],
  130. ],
  131. 'out' => [
  132. 'icmp' => $result['outICMP'],
  133. 'tcp' => $result['outTCP'],
  134. ],
  135. ];
  136. }
  137. Log::warning('【阻断检测】检测'.$ip.'时,[vps234]接口返回'.var_export($data, true));
  138. }
  139. Log::warning("【阻断检测】检测{$ip}时, [vps234]接口返回异常");
  140. }
  141. return null;
  142. }
  143. private function flyzy2005(string $ip, int $port): ?array
  144. { // 开发依据: https://www.flyzy2005.cn/tech/ip-check/
  145. $response_inner = self::$basicRequest->get("https://mini.flyzy2005.cn/ip_check.php?ip=$ip&port=$port");
  146. $response_outer = self::$basicRequest->get("https://mini.flyzy2005.cn/ip_check_outside.php?ip=$ip&port=$port");
  147. if ($response_inner->ok() && $response_outer->ok()) {
  148. return $this->common_detection($response_inner->json(), $response_outer->json(), $ip);
  149. }
  150. return null;
  151. }
  152. private function idcoffer(string $ip, int $port): ?array
  153. { // 开发依据: https://www.idcoffer.com/ipcheck
  154. $response_inner = self::$basicRequest->get("https://api.24kplus.com/ipcheck?host=$ip&port=$port");
  155. $response_outer = self::$basicRequest->get("https://api.idcoffer.com/ipcheck?host=$ip&port=$port");
  156. if ($response_inner->ok() && $response_outer->ok()) {
  157. $inner = $response_inner->json();
  158. $outer = $response_outer->json();
  159. if ($inner && $outer) {
  160. if ($inner['code'] && $outer['code']) {
  161. return [
  162. 'in' => [
  163. 'icmp' => $inner['data']['ping'],
  164. 'tcp' => $inner['data']['tcp'],
  165. ],
  166. 'out' => [
  167. 'icmp' => $outer['data']['ping'],
  168. 'tcp' => $outer['data']['tcp'],
  169. ],
  170. ];
  171. }
  172. Log::warning('【阻断检测】检测'.$ip.$port.'时,[idcoffer]接口返回'.var_export($inner, true).PHP_EOL.var_export($outer, true));
  173. }
  174. Log::warning("【阻断检测】检测{$ip}时,[idcoffer]接口返回异常");
  175. }
  176. return null;
  177. }
  178. private function ip112(string $ip, int $port = 443): ?array
  179. { // 开发依据: https://ip112.cn/
  180. $response_inner = self::$basicRequest->asForm()->post('https://api.ycwxgzs.com/ipcheck/index.php', ['ip' => $ip, 'port' => $port]);
  181. $response_outer = self::$basicRequest->asForm()->post('https://api.52bwg.com/ipcheck/ipcheck.php', ['ip' => $ip, 'port' => $port]);
  182. if ($response_inner->ok() && $response_outer->ok()) {
  183. $inner = $response_inner->json();
  184. $outer = $response_outer->json();
  185. if ($inner && $outer) {
  186. return [
  187. 'in' => [
  188. 'icmp' => str_contains($inner['icmp'], 'green'),
  189. 'tcp' => str_contains($inner['tcp'], 'green'),
  190. ],
  191. 'out' => [
  192. 'icmp' => str_contains($outer['icmp'], 'green'),
  193. 'tcp' => str_contains($outer['tcp'], 'green'),
  194. ],
  195. ];
  196. }
  197. }
  198. Log::warning("【阻断检测】检测{$ip}时,[ip112]接口返回异常");
  199. return null;
  200. }
  201. private function upx8(string $ip, int $port = 443): ?array
  202. { // 开发依据: https://blog.upx8.com/ipcha.html
  203. $response_inner = self::$basicRequest->asForm()->post('https://ip.upx8.com/check.php', ['ip' => $ip, 'port' => $port]);
  204. $response_outer = self::$basicRequest->asForm()->post('https://ip.7761.cf/check.php', ['ip' => $ip, 'port' => $port]);
  205. if ($response_inner->ok() && $response_outer->ok()) {
  206. $inner = $response_inner->json();
  207. $outer = $response_outer->json();
  208. if ($inner && $outer) {
  209. return [
  210. 'in' => [
  211. 'icmp' => $inner['icmp'] === '正常',
  212. 'tcp' => $inner['tcp'] === '正常',
  213. ],
  214. 'out' => [
  215. 'icmp' => $outer['icmp'] === '正常',
  216. 'tcp' => $outer['tcp'] === '正常',
  217. ],
  218. ];
  219. }
  220. }
  221. Log::warning("【阻断检测】检测{$ip}时,[upx8]接口返回异常");
  222. return null;
  223. }
  224. private function vps1352(string $ip, int $port): ?array
  225. { // 开发依据: https://www.51vps.info/ipcheck.html https://www.vps1352.com/ipcheck.html 有缺陷api,查不了海外做判断 备用
  226. $response = self::$basicRequest->asForm()->withHeader('Referer', 'https://www.51vps.info')->post('https://www.vps1352.com/check.php', ['ip' => $ip, 'port' => $port]);
  227. if ($response->ok()) {
  228. $data = $response->json();
  229. if ($data) {
  230. return [
  231. 'in' => [
  232. 'icmp' => $data['icmp'] === '开放',
  233. 'tcp' => $data['tcp'] === '开放',
  234. ],
  235. 'out' => [
  236. 'icmp' => true,
  237. 'tcp' => true,
  238. ],
  239. ];
  240. }
  241. }
  242. Log::warning("【阻断检测】检测{$ip}时, [vps1352.com]接口返回异常");
  243. return null;
  244. }
  245. private function rss(string $ip, int $port): ?array
  246. { // https://ip.rss.ink/index/check
  247. $client = self::$basicRequest->withHeader('X-Token', '5AXfB1xVfuq5hxv4');
  248. foreach (['in', 'out'] as $type) {
  249. foreach (['icmp', 'tcp'] as $protocol) {
  250. $response = $client->get('https://ip.rss.ink/netcheck/'.($type === 'in' ? 'cn' : 'global')."/api/check/$protocol?ip=$ip".($protocol === 'tcp' ? "&port=$port" : ''));
  251. if ($response->ok()) {
  252. $data = $response->json();
  253. $ret[$type][$protocol] = $data['msg'] === 'success';
  254. }
  255. }
  256. }
  257. if (! isset($ret)) {
  258. Log::warning("【阻断检测】检测{$ip}时, [rss]接口返回异常");
  259. }
  260. return $ret ?? null;
  261. }
  262. }