Skip to content

Commit

Permalink
Add PTRBlacklist #834
Browse files Browse the repository at this point in the history
WebUI need follow up
  • Loading branch information
Ghost-chu committed Dec 27, 2024
1 parent 1d7b1ea commit 1c0e387
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ public ProfileUpdateScript(YamlConfiguration conf) {
this.conf = conf;
}


@UpdateScript(version = 23)
public void ptrBlacklist(YamlConfiguration bundled) {
conf.set("module.ptr-blacklist", bundled.get("module.ptr-blacklist"));
}

@UpdateScript(version = 22)
public void workaroundForBadWebUI() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package com.ghostchu.peerbanhelper.module.impl.rule;

import com.ghostchu.peerbanhelper.Main;
import com.ghostchu.peerbanhelper.downloader.Downloader;
import com.ghostchu.peerbanhelper.lab.Experiments;
import com.ghostchu.peerbanhelper.lab.Laboratory;
import com.ghostchu.peerbanhelper.module.AbstractRuleFeatureModule;
import com.ghostchu.peerbanhelper.module.CheckResult;
import com.ghostchu.peerbanhelper.module.PeerAction;
import com.ghostchu.peerbanhelper.peer.Peer;
import com.ghostchu.peerbanhelper.text.Lang;
import com.ghostchu.peerbanhelper.text.TranslationComponent;
import com.ghostchu.peerbanhelper.torrent.Torrent;
import com.ghostchu.peerbanhelper.util.context.IgnoreScan;
import com.ghostchu.peerbanhelper.util.dns.DNSLookup;
import com.ghostchu.peerbanhelper.util.rule.Rule;
import com.ghostchu.peerbanhelper.util.rule.RuleMatchResult;
import com.ghostchu.peerbanhelper.util.rule.RuleParser;
import com.ghostchu.peerbanhelper.web.JavalinWebContainer;
import com.ghostchu.peerbanhelper.web.Role;
import com.ghostchu.peerbanhelper.web.wrapper.StdResp;
import com.ghostchu.simplereloadlib.ReloadResult;
import com.ghostchu.simplereloadlib.Reloadable;
import io.javalin.http.Context;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;

@Component
@IgnoreScan
public class PTRBlacklist extends AbstractRuleFeatureModule implements Reloadable {
private List<Rule> ptrRules;
@Autowired
private JavalinWebContainer webContainer;
@Autowired
private DNSLookup dnsLookup;
private long banDuration;
private Laboratory laboratory;

@Override
public @NotNull String getName() {
return "PTR Blacklist";
}

@Override
public @NotNull String getConfigName() {
return "ptr-blacklist";
}


@Override
public boolean isConfigurable() {
return true;
}


@Override
public void onEnable() {
reloadConfig();
webContainer.javalin()
.get("/api/modules/" + getConfigName(), this::handleWebAPI, Role.USER_READ);
Main.getReloadManager().register(this);
}

@Override
public boolean isThreadSafe() {
return true;
}

private void handleWebAPI(Context ctx) {
String locale = locale(ctx);
ctx.json(new StdResp(true, null, Map.of("ptr-rules", ptrRules.stream().map(r -> r.toPrintableText(locale)).toList())));
}

@Override
public void onDisable() {
Main.getReloadManager().unregister(this);
}

@Override
public ReloadResult reloadModule() throws Exception {
reloadConfig();
return Reloadable.super.reloadModule();
}

public void reloadConfig() {
this.banDuration = getConfig().getLong("ban-duration", 0);
this.ptrRules = RuleParser.parse(getConfig().getStringList("ptr-rules"));
getCache().invalidateAll();
}

@Override
public @NotNull CheckResult shouldBanPeer(@NotNull Torrent torrent, @NotNull Peer peer, @NotNull Downloader downloader, @NotNull ExecutorService ruleExecuteExecutor) {
var reverseDnsLookupString = peer.getPeerAddress().getAddress().toReverseDNSLookupString();
return getCache().readCache(this, reverseDnsLookupString, () -> {
Optional<String> ptr;
if (laboratory.isExperimentActivated(Experiments.DNSJAVA.getExperiment())) {
ptr = dnsLookup.ptr(reverseDnsLookupString).join();
} else {
try {
ptr = Optional.ofNullable(InetAddress.getByName(peer.getPeerAddress().getIp()).getHostName());
} catch (UnknownHostException e) {
ptr = Optional.empty();
}
}
if (ptr.isPresent()) {
RuleMatchResult matchResult = RuleParser.matchRule(ptrRules, ptr.get());
if (matchResult.hit()) {
return new CheckResult(getClass(), PeerAction.BAN, banDuration, new TranslationComponent(matchResult.rule().toString()),
new TranslationComponent(Lang.MODULE_PTR_MATCH_PTR_RULE, matchResult.rule().toString()));
}
}
return pass();
}, true);
}

}
15 changes: 14 additions & 1 deletion src/main/java/com/ghostchu/peerbanhelper/text/Lang.java
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,20 @@ public enum Lang {
FREE_LICENSE_DESCRIPTION,
FREE_LICENSE_SOURCE,
FREE_LICENSE_LICENSE_TO,
FREE_LICENSE_RENEW_STILL_ACTIVE, PBH_PLUS_LICENSE_UPDATED, DOWNLOADER_QB_DISABLE_SAME_IP_MULTI_CONNECTION_FAILED, DOWNLOADER_PAUSED, LAB_EXPERIMENT_DNSJAVA_TITLE, LAB_EXPERIMENT_DNSJAVA_DESCRIPTION, LAB_EXPERIMENT_SQLITE_VACUUM_TITLE, LAB_EXPERIMENT_SQLITE_VACUUM_DESCRIPTION, SQLITE_VACUUM_BACKUP_FAILED, SQLITE_VACUUM_BACKUP, SQLITE_VACUUM_BACKUP_COMPLETED, SQLITE_VACUUM_IN_PROGRESS, SQLITE_VACUUM_SUCCESS;
FREE_LICENSE_RENEW_STILL_ACTIVE,
PBH_PLUS_LICENSE_UPDATED,
DOWNLOADER_QB_DISABLE_SAME_IP_MULTI_CONNECTION_FAILED,
DOWNLOADER_PAUSED,
LAB_EXPERIMENT_DNSJAVA_TITLE,
LAB_EXPERIMENT_DNSJAVA_DESCRIPTION,
LAB_EXPERIMENT_SQLITE_VACUUM_TITLE,
LAB_EXPERIMENT_SQLITE_VACUUM_DESCRIPTION,
SQLITE_VACUUM_BACKUP_FAILED,
SQLITE_VACUUM_BACKUP,
SQLITE_VACUUM_BACKUP_COMPLETED,
SQLITE_VACUUM_IN_PROGRESS,
SQLITE_VACUUM_SUCCESS,
MODULE_PTR_MATCH_PTR_RULE;

public String getKey() {
return name();
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/lang/en_us/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -544,4 +544,5 @@ SQLITE_VACUUM_BACKUP: "Backing up SQLite database file for vacuum operation..."
SQLITE_VACUUM_BACKUP_COMPLETED: "SQLite database file backup completed, preparing for vacuum..."
SQLITE_VACUUM_BACKUP_FAILED: "SQLite database file backup failed, unable to perform vacuum operation. This may be due to insufficient disk space, IO errors, or insufficient permissions. Please check the error message."
SQLITE_VACUUM_IN_PROGRESS: "Vacuuming SQLite database in progress, do not close PeerBanHelper as it may cause database corruption! [In Progress]...."
SQLITE_VACUUM_SUCCESS: "SQLite database vacuumed successfully, original file size: {} vacuumed file size: {}"
SQLITE_VACUUM_SUCCESS: "SQLite database vacuumed successfully, original file size: {} vacuumed file size: {}"
MODULE_PTR_MATCH_PTR_RULE: "Match PTR rule: {}"
3 changes: 2 additions & 1 deletion src/main/resources/lang/messages_fallback.yml
Original file line number Diff line number Diff line change
Expand Up @@ -544,4 +544,5 @@ SQLITE_VACUUM_BACKUP: "正在备份 SQLite 数据库文件以便对数据库进
SQLITE_VACUUM_BACKUP_COMPLETED: "SQLite 数据库文件备份完成,准备进行真空……"
SQLITE_VACUUM_BACKUP_FAILED: "SQLite 数据库文件备份失败,无法进行真空操作,这可能是由于磁盘空间不足,IO 错误或者权限不足导致的,请检查错误信息。"
SQLITE_VACUUM_IN_PROGRESS: "正在对 SQLite 数据库进行真空操作,请勿关闭 PeerBanHelper 否则将可能导致数据库损坏! 【进行中】...."
SQLITE_VACUUM_SUCCESS: "SQLite 数据库已成功真空,原文件大小: {} 真空后文件大小: {}"
SQLITE_VACUUM_SUCCESS: "SQLite 数据库已成功真空,原文件大小: {} 真空后文件大小: {}"
MODULE_PTR_MATCH_PTR_RULE: "匹配 PTR 规则: {}"
3 changes: 2 additions & 1 deletion src/main/resources/lang/zh_cn/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -541,4 +541,5 @@ SQLITE_VACUUM_BACKUP: "正在备份 SQLite 数据库文件以便对数据库进
SQLITE_VACUUM_BACKUP_COMPLETED: "SQLite 数据库文件备份完成,准备进行真空……"
SQLITE_VACUUM_BACKUP_FAILED: "SQLite 数据库文件备份失败,无法进行真空操作,这可能是由于磁盘空间不足,IO 错误或者权限不足导致的,请检查错误信息。"
SQLITE_VACUUM_IN_PROGRESS: "正在对 SQLite 数据库进行真空操作,请勿关闭 PeerBanHelper 否则将可能导致数据库损坏! 【进行中】...."
SQLITE_VACUUM_SUCCESS: "SQLite 数据库已成功真空,原文件大小: {} 真空后文件大小: {}"
SQLITE_VACUUM_SUCCESS: "SQLite 数据库已成功真空,原文件大小: {} 真空后文件大小: {}"
MODULE_PTR_MATCH_PTR_RULE: "匹配 PTR 规则: {}"
34 changes: 32 additions & 2 deletions src/main/resources/profile.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
config-version: 22
config-version: 23
# Check interval (Timeunit: ms)
# 检查频率(单位:毫秒)
check-interval: 5000
Expand Down Expand Up @@ -412,4 +412,34 @@ module:
traffic-monitoring:
# 每日阈值 - 设置为 -1 以禁用,单位:bytes
# Daily threshold, set to -1 to disable, Unit: bytes
daily: -1
daily: -1
# PTR (反向解析记录) 封禁
# 此模块将强制对 Peer IP 进行 PTR 查询,并试图解析其 IP 地址绑定的主机名。如果 IP 地址绑定了一个主机名且主机名匹配下列规则,则执行操作
# PTR (Reverse DNS) Blocker
# This module will force to do PTR query on Peer IP, and try to resolve the hostname that bind with IP address. If the IP address bind with a hostname and the hostname match the rules below, then do the action
ptr-blacklist:
enabled: false
# 封禁时间,单位:毫秒,使用 default 则跟随全局设置
# BanDuration, Timeunit: ms, use `default` to fallback to global settings
ban-duration: 259200000
# method = 匹配方式 - Match Method
# + STARTS_WITH = 匹配开头 - Match the starts
# + ENDS_WITH = 匹配结尾 - Match the ends
# + LENGTH = 匹配字符串长度 - Match the string length
# + 支持的额外字段 - Other supported fields
# * min = 最小长度 - Min length
# * max = 最大长度 - Max length
# + CONTAINS = 匹配包含 - Match the contains
# + EQUALS = 匹配相同 - Match the equals
# + REGEX = 匹配正则表达式(大小写敏感) - Match the regex (case-sensitive)
# content = 匹配的内容(除正则外忽略大小写) - The content will be matched
# if = 表达式控制器,当 if 的表达式为 true 时,则检查此规则;否则此规则被忽略。 # if controller, `0` or `false` will skip this rule
# + if 表达式可以为 true/false, 1/0 或者一个嵌套的规则 # the return result can be `true` or `false` and `0` or `1`
# hit = 匹配成功返回的行为代码 # the behavior if matched
# + TRUE = 在 if 中代表 true,在规则中代表 BAN(封禁) # true in if controller, BAN in rule
# + FALSE = 在 if 中代表 false,在规则中代表 SKIP(排除) # false in if controller, SKIP in rule
# + DEFAULT = 在 if 中代表 true,在规则中代表 NO_ACTION(默认行为) # true in if controller, NO_ACTION in rule
# miss = 匹配失败返回的行为代码(与上相同) # the behavior if match failed, same as above
# 规则从上到下执行
ptr-rules:
- '{"method":"EQUALS","content":"example.com"}'

0 comments on commit 1c0e387

Please sign in to comment.