三种作弊检测方法:1,上传下载速度异常检测,2,异常客户端检测,3,上传下载量一致检测
Change-Id: I9949b20c4982ef1a5c8974f9f58928462759b5a6
diff --git a/src/main/java/com/pt5/pthouduan/entity/TrackeredTorrentWithStats.java b/src/main/java/com/pt5/pthouduan/entity/TrackeredTorrentWithStats.java
index 6f015d2..21cc304 100644
--- a/src/main/java/com/pt5/pthouduan/entity/TrackeredTorrentWithStats.java
+++ b/src/main/java/com/pt5/pthouduan/entity/TrackeredTorrentWithStats.java
@@ -49,6 +49,20 @@
long deltaDownloaded = Math.max(0,downloaded - last[1]);
lastStats.put(peerUID,new long[]{uploaded,downloaded});
//updatePeerStatsInDB(this.getHexInfoHash(),ip,port,hexPeerId,uploaded,downloaded,deltaUpload,deltaDownloaded,passkey);
+ //检测异常流量
+ final long ABNORMAL_THRESHOLD = 1073741824L; // 1GB 阈值
+ if (deltaUpload > ABNORMAL_THRESHOLD || deltaDownloaded > ABNORMAL_THRESHOLD) {
+ // 调用服务层记录异常
+ statsService.recordTrafficAnomaly(
+ this.getHexInfoHash(), // info_hash
+ ip, // peer IP
+ port, // peer 端口
+ deltaUpload, // 上传增量
+ deltaDownloaded // 下载增量
+ );
+ }
+
+
try {
// 调用服务层更新统计
statsService.updatePeerStatsInDB(
diff --git a/src/main/java/com/pt5/pthouduan/service/impl/updatePeerStatsService.java b/src/main/java/com/pt5/pthouduan/service/impl/updatePeerStatsService.java
index bdcdc65..9548da6 100644
--- a/src/main/java/com/pt5/pthouduan/service/impl/updatePeerStatsService.java
+++ b/src/main/java/com/pt5/pthouduan/service/impl/updatePeerStatsService.java
@@ -9,6 +9,7 @@
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
import static com.pt5.pthouduan.util.TorrentUtils.hexStringToByteArray;
@@ -33,6 +34,11 @@
int intervalSeconds = 100;
String username = userMapper.getUsernameByPasskey(passkey); // ← 获取用户名
String client = parseClientFromPeerId(peerId); // ← 解析客户端
+ // 记录可疑客户端
+ if (client.startsWith("Suspicious_") || client.startsWith("Blacklisted_")||client.startsWith("Other")) {
+ recordSuspiciousClient(infoHash, ip, port, peerId, client);
+ }
+
System.out.println("剩下的:" + left);
boolean isCompleted = left == 0;
double uploadSpeed = intervalSeconds > 0 ? (double) deltaUpload / intervalSeconds : 0.0;
@@ -134,8 +140,97 @@
if (decodedPeerId.startsWith("-AZ")) return "Azureus";
if (decodedPeerId.startsWith("-LT")) return "libtorrent";
if (decodedPeerId.startsWith("-qB")) return "qBittorrent";
+ if (decodedPeerId.startsWith("-DE")) return "Deluge"; // 新增:Deluge客户端
+ if (decodedPeerId.startsWith("-BT")) return "BitTorrent"; // 新增:BitTorrent客户端
+
+ // 黑名单客户端识别
+ if (decodedPeerId.startsWith("-FAKE")) return "Blacklisted_FakeClient"; // 伪造客户端
+ if (decodedPeerId.startsWith("-HACK")) return "Blacklisted_HackedClient"; // 破解客户端
+ // 未识别的非常见客户端(长度不足或无匹配前缀)
+ if (decodedPeerId.length() < 6) return "Suspicious_TooShort"; // 长度异常
+
+
+
return "Other";
}
+ //记录流量异常
+ public void recordTrafficAnomaly(String infoHash, String ip, int port, long uploadDelta, long downloadDelta) {
+ String sql = """
+ INSERT INTO traffic_anomaly (info_hash, ip, port, upload_delta, download_delta)
+ VALUES (?, ?, ?, ?, ?)
+ """;
+ try (Connection conn = dataSource.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, infoHash);
+ stmt.setString(2, ip);
+ stmt.setInt(3, port);
+ stmt.setLong(4, uploadDelta);
+ stmt.setLong(5, downloadDelta);
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ //logger.error("记录流量异常失败,info_hash={}, ip={}:{}", infoHash, ip, port, e);
+ }
+ }
+ //记录可疑客户端
+ public void recordSuspiciousClient(String infoHash, String ip, int port, String peerId, String clientType) {
+ String sql = """
+ INSERT INTO client_anomaly (info_hash, ip, port, peer_id, client_type)
+ VALUES (?, ?, ?, ?, ?)
+ """;
+ try (Connection conn = dataSource.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(sql)) {
+ stmt.setString(1, infoHash);
+ stmt.setString(2, ip);
+ stmt.setInt(3, port);
+ stmt.setString(4, peerId);
+ stmt.setString(5, clientType);
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ //logger.error("记录可疑客户端失败,info_hash={}, ip={}:{}", infoHash, ip, port, e);
+ }
+ }
+ // 验证指定种子的上传总量与下载总量是否一致
+ public void verifyFileTrafficConsistency(String infoHash) {
+ String querySql = """
+ SELECT
+ SUM(uploaded) AS total_upload,
+ SUM(downloaded) AS total_download,
+ MIN(created_at) AS first_seen_time -- 获取种子首次出现时间
+ FROM peer_stats
+ WHERE info_hash = ?
+ """;
+ String insertAnomalySql = "INSERT INTO file_traffic_anomaly (info_hash, total_upload, total_download, create_time) VALUES (?, ?, ?, NOW())";
+
+ try (Connection conn = dataSource.getConnection();
+ PreparedStatement queryStmt = conn.prepareStatement(querySql);
+ PreparedStatement anomalyStmt = conn.prepareStatement(insertAnomalySql)) {
+
+ queryStmt.setString(1, infoHash);
+ ResultSet rs = queryStmt.executeQuery();
+ if (rs.next()) {
+ long totalUpload = rs.getLong("total_upload");
+ long totalDownload = rs.getLong("total_download");
+ java.sql.Timestamp firstSeen = rs.getTimestamp("first_seen_time");
+
+ // 忽略种子创建后1小时内的不平衡
+ if (firstSeen != null && System.currentTimeMillis() - firstSeen.getTime() < 3600_000) {
+ return;
+ }
+ // 上传总量应等于下载总量(允许±1B误差避免计算精度问题)
+ if (Math.abs(totalUpload - totalDownload) > 1) {
+ // logger.warn("检测到异常种子,info_hash={},总上传={},总下载={}", infoHash, totalUpload, totalDownload);
+
+ // 记录异常到数据库
+ anomalyStmt.setString(1, infoHash);
+ anomalyStmt.setLong(2, totalUpload);
+ anomalyStmt.setLong(3, totalDownload);
+ anomalyStmt.executeUpdate();
+ }
+ }
+ } catch (SQLException e) {
+ //logger.error("验证种子流量一致性失败,info_hash={}", infoHash, e);
+ }
+ }
}