Compare commits

..

12 Commits

16 changed files with 360 additions and 147 deletions

View File

@@ -243,53 +243,55 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
检测18个数据库的IP相关信息多个平台比较对应检测项目都为对应值证明当前IP确实如此不要仅相信一个数据库源的信息:
[ipinfo.io](https://ipinfo.io) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com)
[ipinfo.io](https://ipinfo.io) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com) [cloudflare.com](https://www.cloudflare.com/)
以下为每个字段的对应的含义
| 字段类别 | 字段名称 | 字段说明 | 可能的值 | 评分规则 |
|---------|---------|---------|---------|---------|
| 安全得分 | 声誉(Reputation) | IP地址在安全社区中的信誉评分 | 0-100的数值 | 越高越好 |
| | 信任得分(Trust Score) | IP地址的可信任程度评分 | 0-100的数值 | 越高越好 |
| | VPN得分(VPN Score) | IP被识别为VPN的可能性评分 | 0-100的数值 | 越低越好 |
| | 代理得分(Proxy Score) | IP被识别为代理的可能性评分 | 0-100的数值 | 越低越好 |
| 安全得分 | 声誉 | IP地址在安全社区中的信誉评分 | 0-100的数值 | 越高越好 |
| | 信任得分 | IP地址的可信任程度评分 | 0-100的数值 | 越高越好 |
| | VPN得分 | IP被识别为VPN的可能性评分 | 0-100的数值 | 越低越好 |
| | 代理得分 | IP被识别为代理的可能性评分 | 0-100的数值 | 越低越好 |
| | 社区投票-无害 | 社区成员投票认为该IP无害的分数 | 非负整数 | 越高越好 |
| | 社区投票-恶意 | 社区成员投票认为该IP恶意的分数 | 非负整数 | 越低越好 |
| | 威胁得分(Threat Score) | IP地址的整体威胁程度评分 | 0-100的数值 | 越低越好 |
| | 欺诈得分(Fraud Score) | IP地址涉及欺诈活动的可能性评分 | 0-100的数值 | 越低越好 |
| | 滥用得分(Abuse Score) | IP地址被报告滥用行为的评分 | 0-100的数值 | 越低越好 |
| | 威胁得分 | IP地址的整体威胁程度评分 | 0-100的数值 | 越低越好 |
| | 欺诈得分 | IP地址涉及欺诈活动的可能性评分 | 0-100的数值 | 越低越好 |
| | 滥用得分 | IP地址被报告滥用行为的评分 | 0-100的数值 | 越低越好 |
| | ASN滥用得分 | 该IP所属ASN(自治系统)的滥用评分 | 0-1的小数可能带有风险等级标注(Low/Medium/High) | 越低越好 |
| | 公司滥用得分 | 该IP所属公司的滥用评分 | 0-1的小数可能带有风险等级标注(Low/Medium/High) | 越低越好 |
| | 威胁级别(Threat Level) | IP地址的威胁等级分类 | low/medium/high/critical等文本描述 | low为最佳 |
| 黑名单记录 | 无害记录数(Harmless) | 在各黑名单数据库中被标记为无害的次数 | 非负整数 | 数值本身无好坏 |
| | 恶意记录数(Malicious) | 在各黑名单数据库中被标记为恶意的次数 | 非负整数 | 越低越好 |
| | 可疑记录数(Suspicious) | 在各黑名单数据库中被标记为可疑的次数 | 非负整数 | 越低越好 |
| | 记录数(Undetected) | 在各黑名单数据库中无任何记录的次数 | 非负整数 | 数值本身无好坏 |
| | 威胁级别 | IP地址的威胁等级分类 | low/medium/high/critical等文本描述 | low为最佳 |
| | 流量占比 | 真人和机器人在本机IP的ASN所在国家的占比 | 百分数 | 真人比越高越好 |
| 黑名单记录 | 无害记录数 | 在各黑名单数据库中被标记为无害的次数 | 非负整数 | 数值本身无好坏 |
| | 恶意记录数 | 在各黑名单数据库中被标记为恶意的次数 | 非负整数 | 越低越好 |
| | 可疑记录数 | 在各黑名单数据库中被标记为可疑的次数 | 非负整数 | 越低越好 |
| | 无记录数 | 在各黑名单数据库中无任何记录的次数 | 非负整数 | 数值本身无好坏 |
| | DNS黑名单-总检查数 | 检查的DNS黑名单数据库总数量 | 正整数 | 数值本身无好坏 |
| | DNS黑名单-干净 | 在DNS黑名单中显示为干净(未列入)的数量 | 非负整数 | 越高越好 |
| | DNS黑名单-已列入 | 在DNS黑名单中已被列入的数量 | 非负整数 | 越低越好 |
| | DNS黑名单-其他 | 在DNS黑名单检查中返回其他状态的数量 | 非负整数 | 数值本身无好坏 |
当本机的IP所在的ASN拥有的IP数量比较少时流量占比可以给你提供网络邻居中有多少是真实流量的占比目前全球的互联网流量的占比约是70%真人30%机器人如果需要比较你就按这个基准对比就行了就知道是不是当前IP的ASN在本国的使用达到了互联网平均水平。
一般来说看下面的使用类型公司类型还有安全信息的判别足矣,上面的安全得分只有多个数据库确认一致才可信,不看也没啥问题。(IDC: 一般买服务器识别成这个的多,就是正常的在数据中心机房广播使用的类型)
| 使用类型 | 说明 |
| ----------- | ---------- |
| hosting | 数据中心网络(IDC) |
| residential | 家庭/住宅网络(家宽) |
| FixedLineISPISP | 固定线路互联网服务提供商(家宽) |
| isp | 固定线路互联网服务提供商(家宽) |
| business | 企业办公网络(商宽) |
| cellular | 移动运营商网络(家宽) |
| education | 教育机构网络(教育网) |
| government | 政府机构网络(政府网) |
| military | 军事网络(政府网) |
| DataCenter/WebHosting/Transit | 数据中心网络(IDC) |
| CDN | 内容分发网络(IDC) |
| 公司类型 | 说明 |
| ------------ | ------------ |
| business | 企业公司(商宽) |
| hosting | 主机/数据中心公司(IDC) |
| FixedLineISPISP | 固定线路互联网服务提供商(家宽) |
| business | 企业公司(商宽) |
| isp | 固定线路互联网服务提供商(家宽) |
| education | 教育机构(教育网) |
| government | 政府机构(政府网) |
@@ -297,6 +299,9 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
| 字段类别 | 字段名称 | 字段说明 | 可能的值 | 评分规则 |
|---------|---------|---------|---------|---------|
| 浏览器类型 | 是否为主流浏览器 | 本机IP的ASN所在国家的占比 | 百分比 | 主流的越多越好 |
| 设备类型 | 是否为桌面移动设备 | 本机IP的ASN所在国家的占比 | 百分比 | 桌面移动设备占比越多越好 |
| 操作系统类型 | 是否为主流操作系统 | 本机IP的ASN所在国家的占比 | 百分比 | 主流的越多越好 |
| 云提供商 | 是否云提供商(Cloud Provider) | 该IP是否属于云服务提供商 | Yes/No | 无好坏之分,仅标识 |
| 数据中心 | 是否数据中心(Data Center) | 该IP是否位于数据中心 | Yes/No | 如果关注解锁No为最佳 |
| 移动设备 | 是否移动设备(Mobile) | 该IP是否来自移动设备网络 | Yes/No | 如果关注解锁Yes为最佳 |
@@ -399,8 +404,7 @@ Abuser 或 Abuse 的滥用得分会直接影响机器的正常使用(中国境
| 中国电信 | 163 | ChinaNet (原163骨干网) | 普通国际出口,延迟高易绕路 | 一般 |
| 中国电信 | CN2 GT | ChinaNet Next Carrying Network (GT) | 较优于163偶有拥堵 | 良好 |
| 中国电信 | CN2 GIA | Global Internet Access(GT) | 直连国际POP低延迟低丢包 | 优质(最好) |
| 中国联通 | 169 | China169骨干网 | 老主干网,常经港美出口 | 一般(少部分优质) |
| 中国联通 | 4837 | Unicom International (AS4837) | 常见国际出口,覆盖广 | 良好 |
| 中国联通 | 4837 | Unicom International (AS4837) | 常见国际出口,覆盖广 | 一般到良好 |
| 中国联通 | 9929 | Unicom Premium / CU-IX | 精品网直连主要IXP延迟低 | 优质 |
| 中国移动 | CMI (AS58453) | China Mobile International | 节点多,对两广(广东广西)优化好 | 两广良好,其他一般 |
| 中国移动 | CMIN2 (AS58807) | China Mobile International N2 | 高质量专线低延迟低丢包对标CN2 | 优质 |
@@ -429,7 +433,7 @@ Abuser 或 Abuse 的滥用得分会直接影响机器的正常使用(中国境
| 中国电信 | CN2 BGP | CN2混合BGP(GIA+GT) | 混合路由性能略低于纯GIA | 良好至优质 |
| 中国电信 | CUII | ChinaNet United International Internet | 面向直连美国的专线 | 优质 |
| 中国电信 | 163+CUII混线 | 163国内段+国际专线出口 | 价格低,性能一般 | 一般 |
| 中国联通 | 169 | China169骨干网 | 老主干网,常经港美出口 | 一般(少部分优质) |
| 中国联通 | 169 | China169骨干网 | 老主干网,一般对接4837 | 一般(少部分优质) |
| 中国联通 | 4837 | Unicom International (AS4837) | 常见国际出口,覆盖广 | 良好 |
| 中国联通 | 9929 | Unicom Premium / CU-IX | 精品网直连IXP低延迟 | 优质 |
| 中国联通 | 9929+4837混BGP | 混合出口(IDC常见优化) | 性能平衡 | 良好 |
@@ -683,7 +687,7 @@ Dependency project: [https://github.com/oneclickvirt/securityCheck](https://gith
Detect IP-related information from 18 databases. Multiple platforms comparing corresponding detection items all show corresponding values, proving that the current IP is indeed as such. Do not only trust information from a single database source:
[ipinfo.io](https://ipinfo.io) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com)
[ipinfo.io](https://ipinfo.io) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com) [cloudflare.com](https://www.cloudflare.com/)
The following are the meanings corresponding to each field
@@ -701,6 +705,7 @@ The following are the meanings corresponding to each field
| | ASN Abuse Score | Abuse score of the ASN (Autonomous System) to which this IP belongs | Decimal from 0-1, may include risk level notation (Low/Medium/High) | Lower is better |
| | Company Abuse Score | Abuse score of the company to which this IP belongs | Decimal from 0-1, may include risk level notation (Low/Medium/High) | Lower is better |
| | Threat Level | Threat level classification of IP address | Text descriptions such as low/medium/high/critical | low is best |
| | Traffic Proportion | Proportion of humans versus bots within the ASN country of the local IP address | Percentage | Higher human proportion is preferable |
| Blacklist Records | Harmless Count | Number of times marked as harmless in various blacklist databases | Non-negative integer | Value itself has no good or bad |
| | Malicious Count | Number of times marked as malicious in various blacklist databases | Non-negative integer | Lower is better |
| | Suspicious Count | Number of times marked as suspicious in various blacklist databases | Non-negative integer | Lower is better |
@@ -710,26 +715,27 @@ The following are the meanings corresponding to each field
| | DNS Blacklist-Listed | Number already listed in DNS blacklists | Non-negative integer | Lower is better |
| | DNS Blacklist-Other | Number returning other statuses in DNS blacklist checks | Non-negative integer | Value itself has no good or bad |
When the ASN to which this device's IP belongs has a relatively small number of IP addresses, the traffic proportion can indicate what percentage of your network neighbors constitute genuine traffic. Currently, global internet traffic is roughly 70% human and 30% bot. If you need a comparison, use this benchmark to determine whether the ASN of your current IP has reached the internet average usage level within your country.
Generally speaking, checking the usage type, company type, and security information below is sufficient. The security score above is only reliable when confirmed by multiple databases, so it's not a problem to skip it. (IDC: generally buy vps identified as this much, is normal in the data center room broadcasting the type of use)
| Usage Type | Description |
| ----------- | ---------- |
| hosting | Data center network (IDC) |
| residential | Home/Residential network (Home broadband) |
| FixedLineISP, ISP | Fixed-line Internet Service Provider (Home broadband) |
| isp | Fixed-line Internet Service Provider (Home broadband) |
| business | Enterprise office network (Business broadband) |
| cellular | Mobile carrier network (Home broadband) |
| education | Educational institution network (Education network) |
| government | Government institution network (Government network) |
| military | Military network (Government network) |
| DataCenter/WebHosting/Transit | Data center network (IDC) |
| CDN | Content Delivery Network (IDC) |
| Company Type | Description |
| ------------ | ------------ |
| business | Business company (Business broadband) |
| hosting | Hosting/Data center company (IDC) |
| FixedLineISP, ISP | Fixed-line Internet Service Provider (Home broadband) |
| business | Business company (Business broadband) |
| isp | Fixed-line Internet Service Provider (Home broadband) |
| education | Educational institution (Education network) |
| government | Government institution (Government network) |
@@ -737,6 +743,9 @@ The above type descriptions represent the original query information types. Duri
| Field Category | Field Name | Field Description | Possible Values | Scoring Rules |
|---------|---------|---------|---------|---------|
| BrowserType | Mainstream Browser | Proportion of ASN Country for Local IP | Percentage | Higher mainstream proportion preferable |
| DeviceType | Desktop or Mobile Device | Percentage of ASN Country for Local IP | Percentage | Higher proportion of desktop/mobile devices is preferable |
| OSType | Mainstream Operating System | Percentage of ASN Country for Local IP | Percentage | Higher proportion of mainstream systems is preferable |
| Cloud Provider | Is Cloud Provider | Whether this IP belongs to a cloud service provider | Yes/No | No good or bad, identification only |
| Data Center | Is Data Center | Whether this IP is located in a data center | Yes/No | No is best if concerned about unblocking |
| Mobile | Is Mobile | Whether this IP is from a mobile device network | Yes/No | Yes is best if concerned about unblocking |
@@ -1017,7 +1026,7 @@ IP品質によるアクセス制限に敏感なのは、実際には主要なAI
18個のデータベースのIP関連情報を検出し、複数のプラットフォームで対応する検出項目がすべて対応する値である場合、現在のIPが確かにそうであることを証明します。1つのデータベースソースの情報のみを信じないでください:
[ipinfo.io](https://ipinfo.io) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com)
[ipinfo.io](https://ipinfo.io) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com) [cloudflare.com](https://www.cloudflare.com/)
以下は各フィールドの対応する意味です
@@ -1035,6 +1044,7 @@ IP品質によるアクセス制限に敏感なのは、実際には主要なAI
| | ASN不正使用スコア | このIPが属するASN(自律システム)の不正使用スコア | 0-1の小数、リスクレベル表記付き(Low/Medium/High)の場合あり | 低いほど良い |
| | 企業不正使用スコア | このIPが属する企業の不正使用スコア | 0-1の小数、リスクレベル表記付き(Low/Medium/High)の場合あり | 低いほど良い |
| | 脅威レベル(Threat Level) | IPアドレスの脅威レベル分類 | low/medium/high/criticalなどのテキスト記述 | lowが最良 |
| | トラフィック比率 | 本機IPのASN所在国における人間とボットの比率 | パーセンテージ | 人間比率が高いほど良い |
| ブラックリスト記録 | 無害記録数(Harmless) | 各ブラックリストデータベースで無害とマークされた回数 | 非負整数 | 数値自体に良し悪しなし |
| | 悪意記録数(Malicious) | 各ブラックリストデータベースで悪意があるとマークされた回数 | 非負整数 | 低いほど良い |
| | 疑わしい記録数(Suspicious) | 各ブラックリストデータベースで疑わしいとマークされた回数 | 非負整数 | 低いほど良い |
@@ -1044,26 +1054,27 @@ IP品質によるアクセス制限に敏感なのは、実際には主要なAI
| | DNSブラックリスト-掲載済み | DNSブラックリストに既に掲載されている数 | 非負整数 | 低いほど良い |
| | DNSブラックリスト-その他 | DNSブラックリストチェックで他のステータスを返した数 | 非負整数 | 数値自体に良し悪しなし |
本機のIPが属するASNが保有するIP数が少ない場合、トラフィック比率からネットワーク内の実際のトラフィック割合を把握できます。現在の全世界インターネットトラフィックの割合は約70%が人間、30%がボットです。比較が必要な場合はこの基準値を基に照らし合わせれば、当該IPのASNが自国内でインターネット平均水準に達しているか判断できます。
一般的に以下の使用タイプ、会社タイプ、そしてセキュリティ情報の判別で十分です。上記のセキュリティスコアは複数のデータベースで一致が確認された場合のみ信頼できるため、見なくても特に問題ありません。(IDC: サーバーを購入する際、一般的にこの識別されることが多い。データセンターのサーバールームでブロードキャストに使用される通常のタイプである)
| 使用タイプ | 説明 |
| ----------- | ---------- |
| hosting | データセンターネットワーク(IDC) |
| residential | 家庭/住宅ネットワーク(家庭用回線) |
| FixedLineISP、ISP | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| isp | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| business | 企業オフィスネットワーク(ビジネス回線) |
| cellular | モバイル通信事業者ネットワーク(家庭用回線) |
| education | 教育機関ネットワーク(教育ネットワーク) |
| government | 政府機関ネットワーク(政府ネットワーク) |
| military | 軍事ネットワーク(政府ネットワーク) |
| DataCenter/WebHosting/Transit | データセンターネットワーク(IDC) |
| CDN | コンテンツ配信ネットワーク(IDC) |
| 会社タイプ | 説明 |
| ------------ | ------------ |
| business | 企業会社(ビジネス回線) |
| hosting | ホスト/データセンター会社(IDC) |
| FixedLineISP、ISP | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| business | 企業会社(ビジネス回線) |
| isp | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| education | 教育機関(教育ネットワーク) |
| government | 政府機関(政府ネットワーク) |
@@ -1071,6 +1082,9 @@ IP品質によるアクセス制限に敏感なのは、実際には主要なAI
| フィールドカテゴリ | フィールド名 | フィールド説明 | 可能な値 | 評価ルール |
|---------|---------|---------|---------|---------|
| ブラウザタイプ | 主流ブラウザかどうか | 本機IPのASN所在国の割合 | パーセンテージ | 主流であるほど良い |
| デバイスタイプ | デスクトップ/モバイルデバイスか | 本機IPのASN所在国の割合 | パーセンテージ | デスクトップとモバイルデバイスの割合が高いほど良い |
| オペレーティングシステムタイプ | 主流OSか | 本機IPのASN所在国の割合 | パーセンテージ | 主流OSが多いほど良い |
| クラウドプロバイダー | クラウドプロバイダーかどうか(Cloud Provider) | このIPがクラウドサービスプロバイダーに属しているか | Yes/No | 良し悪しはなく、識別のみ |
| データセンター | データセンターかどうか(Data Center) | このIPがデータセンターに位置しているか | Yes/No | アンブロックを重視する場合はNoが最適 |
| モバイルデバイス | モバイルデバイスかどうか(Mobile) | このIPがモバイルデバイスネットワークからのものか | Yes/No | アンブロックを重視する場合はYesが最適 |

12
go.mod
View File

@@ -4,18 +4,18 @@ go 1.25.3
require (
github.com/imroc/req/v3 v3.54.0
github.com/oneclickvirt/UnlockTests v0.0.30-20251109035206
github.com/oneclickvirt/backtrace v0.0.8-20251102140847
github.com/oneclickvirt/basics v0.0.16-20251030093657
github.com/oneclickvirt/cputest v0.0.12-20250720122317
github.com/oneclickvirt/UnlockTests v0.0.31-20251111095646
github.com/oneclickvirt/backtrace v0.0.8-20251109090457
github.com/oneclickvirt/basics v0.0.16-20251112033526
github.com/oneclickvirt/cputest v0.0.12-20251111095842
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
github.com/oneclickvirt/disktest v0.0.10-20250924030424
github.com/oneclickvirt/gostun v0.0.5-20250727155022
github.com/oneclickvirt/memorytest v0.0.10-20250924154648
github.com/oneclickvirt/nt3 v0.0.10-20251104114914
github.com/oneclickvirt/nt3 v0.0.10-20251111095706
github.com/oneclickvirt/pingtest v0.0.9-20251104112920
github.com/oneclickvirt/portchecker v0.0.3-20250728015900
github.com/oneclickvirt/security v0.0.7-20251106060213
github.com/oneclickvirt/security v0.0.8-20251112080734
github.com/oneclickvirt/speedtest v0.0.11-20251102151740
)

24
go.sum
View File

@@ -94,14 +94,14 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nxtrace/NTrace-core v1.4.3-rc.1 h1:V19tkw3kKAMQOOh7Ibb/jZFBk4kMUfQYmpxxtsOfYWo=
github.com/nxtrace/NTrace-core v1.4.3-rc.1/go.mod h1:lGhfZ916pEUJh+VzWZTYu7bKBo06pAn+/gXb0A/7gGg=
github.com/oneclickvirt/UnlockTests v0.0.30-20251109035206 h1:c5mUPst0P0K54N5bNbNdme8C2wajSCJxZ/5+p42s7ZY=
github.com/oneclickvirt/UnlockTests v0.0.30-20251109035206/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE=
github.com/oneclickvirt/backtrace v0.0.8-20251102140847 h1:OiwD06+Mql3pYP8jJFFdP3OUlCrx/qJT7y2YCd/OMiI=
github.com/oneclickvirt/backtrace v0.0.8-20251102140847/go.mod h1:mj9TSow7FNszBb3bQj2Hhm41LwBo7HQP6sgaPtovKdM=
github.com/oneclickvirt/basics v0.0.16-20251030093657 h1:6SWWILNjJfMTXbspqYRpktUEOe/QIVhGonKO8ODC7n4=
github.com/oneclickvirt/basics v0.0.16-20251030093657/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg=
github.com/oneclickvirt/cputest v0.0.12-20250720122317 h1:toiwAK1hZE5b8klu2mOQ7J4sv5yV9lpPKwgPahfRYBQ=
github.com/oneclickvirt/cputest v0.0.12-20250720122317/go.mod h1:vjlH8tkPFft1tlLOpeNskXVvurxkHaJ3+dgFxQGLXY4=
github.com/oneclickvirt/UnlockTests v0.0.31-20251111095646 h1:GXwimPara6aY88GNYnTkFQfr/aLPsFATT4aDTRDdVsU=
github.com/oneclickvirt/UnlockTests v0.0.31-20251111095646/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE=
github.com/oneclickvirt/backtrace v0.0.8-20251109090457 h1:599/R/qMAtfPCPG1bPoi6KbjNJzVkKtxm8dvVIdtn5o=
github.com/oneclickvirt/backtrace v0.0.8-20251109090457/go.mod h1:mj9TSow7FNszBb3bQj2Hhm41LwBo7HQP6sgaPtovKdM=
github.com/oneclickvirt/basics v0.0.16-20251112033526 h1:bgoLaqStV3a6mbPiM++0mYizd278GVa6J6yeIiusV+A=
github.com/oneclickvirt/basics v0.0.16-20251112033526/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg=
github.com/oneclickvirt/cputest v0.0.12-20251111095842 h1:ixZUvIkSlsIZfsg+dNDKq/FTofEtUjfA2LtpTrNr/6s=
github.com/oneclickvirt/cputest v0.0.12-20251111095842/go.mod h1:vjlH8tkPFft1tlLOpeNskXVvurxkHaJ3+dgFxQGLXY4=
github.com/oneclickvirt/dd v0.0.2-20250808062818 h1:0KHrKkdpL5oBE1OHsrRd2siRw4/2k6f9LBaP7T4JpOc=
github.com/oneclickvirt/dd v0.0.2-20250808062818/go.mod h1:tImu9sPTkLWo2tf1dEN1xQzrylWKauj9hbU8PHfyAeU=
github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc=
@@ -116,14 +116,14 @@ github.com/oneclickvirt/mbw v0.0.1-20250808061222 h1:WGXOe6QvHiDRhPVMI0VcctjzW08
github.com/oneclickvirt/mbw v0.0.1-20250808061222/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y=
github.com/oneclickvirt/memorytest v0.0.10-20250924154648 h1:trk6oZ7xs1eVtr+6oIv5IX8LDVtEMG+E6GVzQ810BtU=
github.com/oneclickvirt/memorytest v0.0.10-20250924154648/go.mod h1:4kiHsEWkW9r3/1ZcV5xIweU0smiKP0IRfQj74AUIiVI=
github.com/oneclickvirt/nt3 v0.0.10-20251104114914 h1:P4nbdKcIA7+FH4feLLxfiJVf1f3ENi/oo37EsdyX9oI=
github.com/oneclickvirt/nt3 v0.0.10-20251104114914/go.mod h1:yo1ufkduFt9QjqG7nqSUf1D3YlQOmFpdlTYniJfclQI=
github.com/oneclickvirt/nt3 v0.0.10-20251111095706 h1:GEdgL6oAWXY80NIq23mLjcTR3gvLGh9iusFzJK6SoDo=
github.com/oneclickvirt/nt3 v0.0.10-20251111095706/go.mod h1:yo1ufkduFt9QjqG7nqSUf1D3YlQOmFpdlTYniJfclQI=
github.com/oneclickvirt/pingtest v0.0.9-20251104112920 h1:j3Fjhy0YHT/VF7iuAVVELaRXkquvRd64tWWfFLJs01o=
github.com/oneclickvirt/pingtest v0.0.9-20251104112920/go.mod h1:gxwsxxwitNQiGq2OI0ZogYoOLwc8DtuOdSRe6/EvRqs=
github.com/oneclickvirt/portchecker v0.0.3-20250728015900 h1:AomzdppSOFB70AJESQhlp0IPbsHTTJGimAWDk2TzCWM=
github.com/oneclickvirt/portchecker v0.0.3-20250728015900/go.mod h1:9sjMDPCd4Z40wkYB0S9gQPGH8YPtnNE1ZJthVIuHUzA=
github.com/oneclickvirt/security v0.0.7-20251106060213 h1:vBCEFvuWpScXZ9O7Y7cW1zp1V2AfjzMN+YSBcYfpjYs=
github.com/oneclickvirt/security v0.0.7-20251106060213/go.mod h1:YfDilPFW22szjdUNgv4VOuSwHnZzsFsdPOfRYiMoc3I=
github.com/oneclickvirt/security v0.0.8-20251112080734 h1:WpwdGbwpiBP2YA1lNsymati5uvBbWFlN9CXHYgd3/fE=
github.com/oneclickvirt/security v0.0.8-20251112080734/go.mod h1:aPMIwqsz7wiUH1cqvtRr9+QcQRkKzlUWecDM6SGVddc=
github.com/oneclickvirt/speedtest v0.0.11-20251102151740 h1:1NUrNt5ay6/xVNC5x62UrQjPqK8jgbKtyjBml/3boZg=
github.com/oneclickvirt/speedtest v0.0.11-20251102151740/go.mod h1:fy0II2Wo7kDWVBKTwcHdodZwyfmJo0g8N9V02EwQDZE=
github.com/oneclickvirt/stream v0.0.2-20250924154001 h1:GuJWdiPkoK84+y/+oHKr2Ghl3c/MzS9Z5m1nM+lMmy4=

View File

@@ -27,7 +27,7 @@ import (
)
var (
ecsVersion = "v0.1.101" // 融合怪版本号
ecsVersion = "v0.1.104" // 融合怪版本号
configs = params.NewConfig(ecsVersion) // 全局配置实例
userSetFlags = make(map[string]bool) // 用于跟踪哪些参数是用户显式设置的
)
@@ -83,6 +83,7 @@ func main() {
basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string
output, tempOutput string
outputMutex sync.Mutex
infoMutex sync.Mutex // 保护并发字符串写入
)
startTime := time.Now()
uploadDone := make(chan bool, 1)
@@ -91,9 +92,9 @@ func main() {
go runner.HandleSignalInterrupt(sig, configs, &startTime, &output, tempOutput, uploadDone, &outputMutex)
switch configs.Language {
case "zh":
runner.RunChineseTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex)
runner.RunChineseTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex, &infoMutex)
case "en":
runner.RunEnglishTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex)
runner.RunEnglishTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex, &infoMutex)
default:
fmt.Println("Unsupported language")
}

View File

@@ -152,7 +152,7 @@ goecs_check() {
os=$(uname -s 2>/dev/null || echo "Unknown")
arch=$(uname -m 2>/dev/null || echo "Unknown")
check_china
ECS_VERSION="0.1.100"
ECS_VERSION="0.1.103"
for api in \
"https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \
"https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \
@@ -164,8 +164,8 @@ goecs_check() {
sleep 1
done
if [ -z "$ECS_VERSION" ]; then
_yellow "Unable to get version info, using default version 0.1.100"
ECS_VERSION="0.1.100"
_yellow "Unable to get version info, using default version 0.1.103"
ECS_VERSION="0.1.103"
fi
version_output=""
for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do

View File

@@ -21,7 +21,7 @@ func GetMenuChoice(language string) string {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigChan)
inputChan := make(chan string, 1)
go func() {
select {
case <-sigChan:
@@ -31,43 +31,33 @@ func GetMenuChoice(language string) string {
return
}
}()
for {
go func() {
var input string
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
select {
case inputChan <- input:
case <-ctx.Done():
return
}
}()
select {
case input := <-inputChan:
re := regexp.MustCompile(`^\d+$`)
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid choice")
}
}
} else {
var input string
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
re := regexp.MustCompile(`^\d+$`)
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid input, please enter a number")
fmt.Println("Invalid choice")
}
}
case <-ctx.Done():
return ""
} else {
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
} else {
fmt.Println("Invalid input, please enter a number")
}
}
}
}

View File

@@ -210,72 +210,116 @@ func (c *Config) SaveUserSetParams() map[string]interface{} {
// RestoreUserSetParams restores user-set parameters
func (c *Config) RestoreUserSetParams(saved map[string]interface{}) {
if val, ok := saved["basic"]; ok {
c.BasicStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.BasicStatus = boolVal
}
}
if val, ok := saved["cpu"]; ok {
c.CpuTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.CpuTestStatus = boolVal
}
}
if val, ok := saved["memory"]; ok {
c.MemoryTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.MemoryTestStatus = boolVal
}
}
if val, ok := saved["disk"]; ok {
c.DiskTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.DiskTestStatus = boolVal
}
}
if val, ok := saved["ut"]; ok {
c.UtTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.UtTestStatus = boolVal
}
}
if val, ok := saved["security"]; ok {
c.SecurityTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.SecurityTestStatus = boolVal
}
}
if val, ok := saved["email"]; ok {
c.EmailTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.EmailTestStatus = boolVal
}
}
if val, ok := saved["backtrace"]; ok {
c.BacktraceStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.BacktraceStatus = boolVal
}
}
if val, ok := saved["nt3"]; ok {
c.Nt3Status = val.(bool)
if boolVal, ok := val.(bool); ok {
c.Nt3Status = boolVal
}
}
if val, ok := saved["speed"]; ok {
c.SpeedTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.SpeedTestStatus = boolVal
}
}
if val, ok := saved["ping"]; ok {
c.PingTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.PingTestStatus = boolVal
}
}
if val, ok := saved["tgdc"]; ok {
c.TgdcTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.TgdcTestStatus = boolVal
}
}
if val, ok := saved["web"]; ok {
c.WebTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.WebTestStatus = boolVal
}
}
if val, ok := saved["cpum"]; ok {
c.CpuTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.CpuTestMethod = strVal
}
}
if val, ok := saved["cput"]; ok {
c.CpuTestThreadMode = val.(string)
if strVal, ok := val.(string); ok {
c.CpuTestThreadMode = strVal
}
}
if val, ok := saved["memorym"]; ok {
c.MemoryTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.MemoryTestMethod = strVal
}
}
if val, ok := saved["diskm"]; ok {
c.DiskTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.DiskTestMethod = strVal
}
}
if val, ok := saved["diskp"]; ok {
c.DiskTestPath = val.(string)
if strVal, ok := val.(string); ok {
c.DiskTestPath = strVal
}
}
if val, ok := saved["diskmc"]; ok {
c.DiskMultiCheck = val.(bool)
if boolVal, ok := val.(bool); ok {
c.DiskMultiCheck = boolVal
}
}
if val, ok := saved["nt3loc"]; ok {
if c.Choice != "10" {
c.Nt3Location = val.(string)
if strVal, ok := val.(string); ok {
c.Nt3Location = strVal
}
}
}
if val, ok := saved["nt3t"]; ok {
c.Nt3CheckType = val.(string)
if strVal, ok := val.(string); ok {
c.Nt3CheckType = strVal
}
}
if val, ok := saved["spnum"]; ok {
c.SpNum = val.(int)
if intVal, ok := val.(int); ok {
c.SpNum = intVal
}
}
c.ValidateParams()

View File

@@ -2,6 +2,7 @@ package runner
import (
"bufio"
"context"
"fmt"
"os"
"runtime"
@@ -17,7 +18,7 @@ import (
)
// RunChineseTests runs all tests in Chinese mode
func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex) {
func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex, infoMutex *sync.Mutex) {
*output = RunBasicTests(preCheck, config, basicInfo, securityInfo, *output, tempOutput, outputMutex)
*output = RunCPUTest(config, *output, tempOutput, outputMutex)
*output = RunMemoryTest(config, *output, tempOutput, outputMutex)
@@ -29,30 +30,39 @@ func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1,
wg1.Add(1)
go func() {
defer wg1.Done()
*mediaInfo = tests.MediaTest(config.Language)
result := tests.MediaTest(config.Language)
infoMutex.Lock()
*mediaInfo = result
infoMutex.Unlock()
}()
}
if config.EmailTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
wg2.Add(1)
go func() {
defer wg2.Done()
*emailInfo = email.EmailCheck()
result := email.EmailCheck()
infoMutex.Lock()
*emailInfo = result
infoMutex.Unlock()
}()
}
if (config.OnlyChinaTest || config.PingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
wg3.Add(1)
go func() {
defer wg3.Done()
*ptInfo = pt.PingTest()
result := pt.PingTest()
infoMutex.Lock()
*ptInfo = result
infoMutex.Unlock()
}()
}
if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex)
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex, infoMutex)
*output = RunSecurityTests(config, *securityInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex, infoMutex)
}
if runtime.GOOS != "windows" && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = RunNetworkTests(config, wg3, ptInfo, *output, tempOutput, outputMutex)
*output = RunNetworkTests(config, wg3, ptInfo, *output, tempOutput, outputMutex, infoMutex)
}
if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = RunSpeedTests(config, *output, tempOutput, outputMutex)
@@ -61,7 +71,7 @@ func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1,
}
// RunEnglishTests runs all tests in English mode
func RunEnglishTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex) {
func RunEnglishTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex, infoMutex *sync.Mutex) {
*output = RunBasicTests(preCheck, config, basicInfo, securityInfo, *output, tempOutput, outputMutex)
*output = RunCPUTest(config, *output, tempOutput, outputMutex)
*output = RunMemoryTest(config, *output, tempOutput, outputMutex)
@@ -74,19 +84,25 @@ func RunEnglishTests(preCheck utils.NetCheckResult, config *params.Config, wg1,
wg1.Add(1)
go func() {
defer wg1.Done()
*mediaInfo = tests.MediaTest(config.Language)
result := tests.MediaTest(config.Language)
infoMutex.Lock()
*mediaInfo = result
infoMutex.Unlock()
}()
}
if config.EmailTestStatus {
wg2.Add(1)
go func() {
defer wg2.Done()
*emailInfo = email.EmailCheck()
result := email.EmailCheck()
infoMutex.Lock()
*emailInfo = result
infoMutex.Unlock()
}()
}
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex)
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex, infoMutex)
*output = RunSecurityTests(config, *securityInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex, infoMutex)
*output = RunEnglishNetworkTests(config, wg3, ptInfo, *output, tempOutput, outputMutex)
*output = RunEnglishSpeedTests(config, *output, tempOutput, outputMutex)
}
@@ -218,7 +234,7 @@ func RunDiskTest(config *params.Config, output, tempOutput string, outputMutex *
}
// RunStreamingTests runs platform unlock tests
func RunStreamingTests(config *params.Config, wg1 *sync.WaitGroup, mediaInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
func RunStreamingTests(config *params.Config, wg1 *sync.WaitGroup, mediaInfo *string, output, tempOutput string, outputMutex *sync.Mutex, infoMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
@@ -229,7 +245,10 @@ func RunStreamingTests(config *params.Config, wg1 *sync.WaitGroup, mediaInfo *st
} else {
utils.PrintCenteredTitle("Cross-Border-Platform-Unlock", config.Width)
}
fmt.Printf("%s", *mediaInfo)
infoMutex.Lock()
info := *mediaInfo
infoMutex.Unlock()
fmt.Printf("%s", info)
}
}, tempOutput, output)
}
@@ -251,7 +270,7 @@ func RunSecurityTests(config *params.Config, securityInfo, output, tempOutput st
}
// RunEmailTests runs email port tests
func RunEmailTests(config *params.Config, wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
func RunEmailTests(config *params.Config, wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput string, outputMutex *sync.Mutex, infoMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
@@ -262,13 +281,16 @@ func RunEmailTests(config *params.Config, wg2 *sync.WaitGroup, emailInfo *string
} else {
utils.PrintCenteredTitle("Email-Port-Check", config.Width)
}
fmt.Println(*emailInfo)
infoMutex.Lock()
info := *emailInfo
infoMutex.Unlock()
fmt.Println(info)
}
}, tempOutput, output)
}
// RunNetworkTests runs network tests (Chinese mode)
func RunNetworkTests(config *params.Config, wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
func RunNetworkTests(config *params.Config, wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex, infoMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
@@ -280,15 +302,18 @@ func RunNetworkTests(config *params.Config, wg3 *sync.WaitGroup, ptInfo *string,
utils.PrintCenteredTitle("三网回程路由检测", config.Width)
tests.NextTrace3Check(config.Language, config.Nt3Location, config.Nt3CheckType)
}
if config.OnlyChinaTest && *ptInfo != "" {
infoMutex.Lock()
info := *ptInfo
infoMutex.Unlock()
if config.OnlyChinaTest && info != "" {
wg3.Wait()
utils.PrintCenteredTitle("PING值检测", config.Width)
fmt.Println(*ptInfo)
fmt.Println(info)
}
if config.PingTestStatus && *ptInfo != "" {
if config.PingTestStatus && info != "" {
wg3.Wait()
utils.PrintCenteredTitle("PING值检测", config.Width)
fmt.Println(*ptInfo)
fmt.Println(info)
if config.TgdcTestStatus {
fmt.Println(pt.TelegramDCTest())
}
@@ -414,16 +439,26 @@ func HandleSignalInterrupt(sig chan os.Signal, config *params.Config, startTime
httpsURL string
}, 1)
if config.EnableUpload {
// 使用context来控制上传goroutine
uploadCtx, uploadCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer uploadCancel()
go func() {
httpURL, httpsURL := utils.ProcessAndUpload(finalOutput, config.FilePath, config.EnableUpload)
resultChan <- struct {
select {
case resultChan <- struct {
httpURL string
httpsURL string
}{httpURL, httpsURL}
uploadDone <- true
}{httpURL, httpsURL}:
case <-uploadCtx.Done():
// 上传被取消或超时,直接返回
return
}
}()
select {
case result := <-resultChan:
uploadCancel() // 成功完成取消context
if result.httpURL != "" || result.httpsURL != "" {
if config.Language == "en" {
fmt.Printf("Upload successfully!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL)
@@ -437,7 +472,7 @@ func HandleSignalInterrupt(sig chan os.Signal, config *params.Config, startTime
fmt.Scanln()
}
os.Exit(0)
case <-time.After(30 * time.Second):
case <-uploadCtx.Done():
if config.Language == "en" {
fmt.Println("Upload timeout, program exit")
} else {

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -8,6 +10,14 @@ import (
)
func CpuTest(language, testMethod, testThread string) (realTestMethod, res string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] CpuTest panic: %v\n", r)
res = fmt.Sprintf("\nCPU test failed: %v\n", r)
realTestMethod = "error"
}
}()
if runtime.GOOS == "windows" {
if testMethod != "winsat" && testMethod != "" {
// res = "Detected host is Windows, using Winsat for testing.\n"

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -8,6 +10,14 @@ import (
)
func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) (realTestMethod, res string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] DiskTest panic: %v\n", r)
res = fmt.Sprintf("\nDisk test failed: %v\n", r)
realTestMethod = "error"
}
}()
switch testMethod {
case "fio":
res = disk.FioTest(language, isMultiCheck, testPath)

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -8,6 +10,14 @@ import (
)
func MemoryTest(language, testMethod string) (realTestMethod, res string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] MemoryTest panic: %v\n", r)
res = fmt.Sprintf("\nMemory test failed: %v\n", r)
realTestMethod = "error"
}
}()
testMethod = strings.ToLower(testMethod)
if testMethod == "" {
testMethod = "auto"

View File

@@ -2,14 +2,55 @@ package tests
import (
"fmt"
"net"
"os"
"strings"
"github.com/oneclickvirt/nt3/nt"
)
func NextTrace3Check(language, nt3Location, nt3CheckType string) {
// 先检查 ICMP 权限
conn, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
// 没有权限,显示友好提示并跳过
if language == "zh" {
fmt.Println("路由追踪测试需要 root 权限或 CAP_NET_RAW 能力,已跳过")
fmt.Fprintf(os.Stderr, "[WARN] ICMP权限不足: %v\n", err)
} else {
fmt.Println("Route tracing test requires root privileges or CAP_NET_RAW capability, skipped")
fmt.Fprintf(os.Stderr, "[WARN] Insufficient ICMP permission: %v\n", err)
}
return
}
conn.Close()
defer func() {
if r := recover(); r != nil {
if language == "zh" {
fmt.Println("路由追踪测试出现错误,已跳过")
fmt.Fprintf(os.Stderr, "[WARN] 路由追踪panic: %v\n", r)
} else {
fmt.Println("Route tracing test failed, skipped")
fmt.Fprintf(os.Stderr, "[WARN] Route tracing panic: %v\n", r)
}
}
}()
resultChan := make(chan nt.TraceResult, 100)
go nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan)
errorOccurred := false
go func() {
defer func() {
if r := recover(); r != nil {
errorOccurred = true
resultChan <- nt.TraceResult{
Index: -1,
ISPName: "Error",
Output: []string{fmt.Sprintf("Route tracing error: %v", r)},
}
close(resultChan)
}
}()
nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan)
}()
for result := range resultChan {
if result.Index == -1 {
for index, res := range result.Output {
@@ -21,12 +62,18 @@ func NextTrace3Check(language, nt3Location, nt3CheckType string) {
continue
}
if result.ISPName == "Error" {
if language == "zh" {
fmt.Println("路由追踪测试失败(可能因为权限不足),已跳过")
} else {
fmt.Println("Route tracing test failed (possibly due to insufficient permissions), skipped")
}
for _, res := range result.Output {
res = strings.TrimSpace(res)
if res != "" {
fmt.Println(res)
fmt.Fprintf(os.Stderr, "[WARN] %s\n", res)
}
}
errorOccurred = true
continue
}
for _, res := range result.Output {
@@ -41,4 +88,11 @@ func NextTrace3Check(language, nt3Location, nt3CheckType string) {
}
}
}
if errorOccurred {
if language == "zh" {
fmt.Println("提示: 路由追踪需要 root 权限或 CAP_NET_RAW 能力")
} else {
fmt.Println("Hint: Route tracing requires root privileges or CAP_NET_RAW capability")
}
}
}

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -9,10 +11,20 @@ import (
)
func ShowHead(language string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] ShowHead panic: %v\n", r)
}
}()
sp.ShowHead(language)
}
func NearbySP() {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] NearbySP panic: %v\n", r)
}
}()
if runtime.GOOS == "windows" || sp.OfficialAvailableTest() != nil {
sp.NearbySpeedTest()
} else {
@@ -21,6 +33,11 @@ func NearbySP() {
}
func CustomSP(platform, operator string, num int, language string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] CustomSP panic: %v\n", r)
}
}()
var url, parseType string
if strings.ToLower(platform) == "cn" {
if strings.ToLower(operator) == "cmcc" {

View File

@@ -1,12 +1,21 @@
package tests
import (
"fmt"
"os"
"github.com/oneclickvirt/UnlockTests/executor"
"github.com/oneclickvirt/UnlockTests/utils"
"github.com/oneclickvirt/defaultset"
)
func MediaTest(language string) string {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] MediaTest panic: %v\n", r)
}
}()
var res string
readStatus := executor.ReadSelect(language, "0")
if !readStatus {

View File

@@ -2,6 +2,7 @@ package tests
import (
"fmt"
"os"
"sync"
"time"
@@ -29,12 +30,25 @@ type ConcurrentResults struct {
var IPV4, IPV6 string
func UpstreamsCheck() {
// 添加panic恢复机制
defer func() {
if r := recover(); r != nil {
fmt.Println("\n上游检测出现错误已跳过")
fmt.Fprintf(os.Stderr, "[WARN] Upstream check panic: %v\n", r)
}
}()
results := ConcurrentResults{}
var wg sync.WaitGroup
if IPV4 != "" {
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] BGP info panic: %v\n", r)
}
}()
for i := 0; i < 2; i++ {
result, err := bgptools.GetPoPInfo(IPV4)
results.bgpError = err
@@ -51,6 +65,11 @@ func UpstreamsCheck() {
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] Backtrace panic: %v\n", r)
}
}()
result := backtrace.BackTrace(executor.IPV6)
results.backtraceResult = result
}()

View File

@@ -203,19 +203,10 @@ func CaptureOutput(f func()) string {
// 替换标准输出和标准错误输出为管道写入端
os.Stdout = stdoutPipeW
os.Stderr = stderrPipeW
// 恢复标准输出和标准错误输出
defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
stdoutPipeW.Close()
stderrPipeW.Close()
stdoutPipeR.Close()
stderrPipeR.Close()
}()
// 缓冲区
var stdoutBuf, stderrBuf bytes.Buffer
// 并发读取 stdout 和 stderr
done := make(chan struct{})
done := make(chan struct{}, 2)
go func() {
multiWriter := io.MultiWriter(&stdoutBuf, oldStdout)
io.Copy(multiWriter, stdoutPipeR)
@@ -234,6 +225,11 @@ func CaptureOutput(f func()) string {
// 等待两个 goroutine 完成
<-done
<-done
// 恢复标准输出和标准错误输出,并关闭管道读取端
os.Stdout = oldStdout
os.Stderr = oldStderr
stdoutPipeR.Close()
stderrPipeR.Close()
// 返回捕获的输出字符串
// stderrBuf.String()
return stdoutBuf.String()
@@ -317,7 +313,9 @@ func ProcessAndUpload(output string, filePath string, enableUplaod bool) (string
// 使用 defer 来处理 panic
defer func() {
if r := recover(); r != nil {
fmt.Printf("处理上传时发生错误: %v\n", r)
fmt.Fprintf(os.Stderr, "[ERROR] 处理上传时发生严重错误: %v\n", r)
// 可以选择打印堆栈信息以便调试
// debug.PrintStack()
}
}()
// 检查文件是否存在
@@ -425,6 +423,8 @@ func CheckPublicAccess(timeout time.Duration) NetCheckResult {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
// 记录panic但不影响其他检查输出到stderr避免污染主输出
fmt.Fprintf(os.Stderr, "[WARN] Panic in network check for %s (%s): %v\n", tag, addr, r)
}
}()
switch kind {