Skip to content

Commit 8bd0b37

Browse files
author
Simple-Tracker
committed
Improve
1 parent a91234c commit 8bd0b37

9 files changed

Lines changed: 446 additions & 114 deletions

File tree

BTN.go

Lines changed: 132 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ import (
99
"fmt"
1010
"hash/crc32"
1111
"math/rand"
12+
"net"
13+
"strconv"
1214
"strings"
15+
"sync"
1316
"sync/atomic"
1417
"time"
1518

19+
"github.com/dlclark/regexp2"
1620
"github.com/tidwall/jsonc"
1721
)
1822

@@ -80,11 +84,11 @@ type BTN_BanInfo struct {
8084
}
8185

8286
type BTN_RulesStruct struct {
83-
Version string `json:"version"`
84-
PeerID map[string][]RuleEntry `json:"peer_id"`
85-
ClientName map[string][]RuleEntry `json:"client_name"`
86-
IP map[string][]string `json:"ip"`
87-
Port map[string][]string `json:"port"`
87+
Version string `json:"version"`
88+
PeerID map[string][]string `json:"peer_id"`
89+
ClientName map[string][]string `json:"client_name"`
90+
IP map[string][]string `json:"ip"`
91+
Port map[string][]string `json:"port"`
8892
}
8993

9094
type RuleEntry struct {
@@ -93,11 +97,11 @@ type RuleEntry struct {
9397
}
9498

9599
type BTN_ExceptionStruct struct {
96-
Version string `json:"version"`
97-
PeerID map[string][]RuleEntry `json:"peer_id"`
98-
ClientName map[string][]RuleEntry `json:"client_name"`
99-
IP map[string][]string `json:"ip"`
100-
Port map[string][]string `json:"port"`
100+
Version string `json:"version"`
101+
PeerID map[string][]string `json:"peer_id"`
102+
ClientName map[string][]string `json:"client_name"`
103+
IP map[string][]string `json:"ip"`
104+
Port map[string][]string `json:"port"`
101105
}
102106

103107
var btnProtocol = "BTN-Protocol/3.0.0"
@@ -131,6 +135,124 @@ var btn_isTaskRunning atomic.Bool
131135

132136
var btnRules BTN_RulesStruct
133137
var btnExceptions BTN_ExceptionStruct
138+
var btn_regexCache sync.Map // map[string]*regexp2.Regexp
139+
140+
func BTN_MatchEntry(value string, ruleRaw string) bool {
141+
var rule RuleEntry
142+
if err := json.Unmarshal([]byte(ruleRaw), &rule); err != nil {
143+
// 某些规则可能直接是字符串内容 (Legacy).
144+
return strings.Contains(value, ruleRaw)
145+
}
146+
147+
switch strings.ToUpper(rule.Method) {
148+
case "EQUALS":
149+
return value == rule.Content
150+
case "STARTS_WITH":
151+
return strings.HasPrefix(value, rule.Content)
152+
case "ENDS_WITH":
153+
return strings.HasSuffix(value, rule.Content)
154+
case "CONTAINS":
155+
return strings.Contains(value, rule.Content)
156+
case "REGEX":
157+
var re *regexp2.Regexp
158+
if val, ok := btn_regexCache.Load(rule.Content); ok {
159+
re = val.(*regexp2.Regexp)
160+
} else {
161+
var err error
162+
re, err = regexp2.Compile(rule.Content, regexp2.IgnoreCase)
163+
if err != nil {
164+
Log("BTN_MatchEntry", "Invalid regex: %s", true, rule.Content)
165+
return false
166+
}
167+
btn_regexCache.Store(rule.Content, re)
168+
}
169+
match, _ := re.MatchString(value)
170+
return match
171+
}
172+
return false
173+
}
174+
175+
func BTN_CheckPeer(peerIP, peerID, peerClient string, peerPort int) (bool, int, string) {
176+
if btnConfig == nil {
177+
return false, 0, ""
178+
}
179+
180+
ipObj := net.ParseIP(peerIP)
181+
peerPortStr := strconv.Itoa(peerPort)
182+
183+
// 1. 检查例外规则 (WhiteList).
184+
for _, rules := range btnExceptions.IP {
185+
for _, rule := range rules {
186+
_, subnet, err := net.ParseCIDR(rule)
187+
if err == nil {
188+
if subnet.Contains(ipObj) {
189+
return false, 0, ""
190+
}
191+
} else if rule == peerIP {
192+
return false, 0, ""
193+
}
194+
}
195+
}
196+
for _, rules := range btnExceptions.Port {
197+
for _, rule := range rules {
198+
if rule == peerPortStr || rule == "ALL" {
199+
return false, 0, ""
200+
}
201+
}
202+
}
203+
for _, rules := range btnExceptions.PeerID {
204+
for _, rule := range rules {
205+
if BTN_MatchEntry(peerID, rule) {
206+
return false, 0, ""
207+
}
208+
}
209+
}
210+
for _, rules := range btnExceptions.ClientName {
211+
for _, rule := range rules {
212+
if BTN_MatchEntry(peerClient, rule) {
213+
return false, 0, ""
214+
}
215+
}
216+
}
217+
218+
// 2. 检查封禁规则 (BlockList).
219+
// 处理顺序: IP -> Port -> PeerID -> ClientName.
220+
for reason, rules := range btnRules.IP {
221+
for _, rule := range rules {
222+
_, subnet, err := net.ParseCIDR(rule)
223+
if err == nil {
224+
if subnet.Contains(ipObj) {
225+
return true, -1, "Bad-IP_FromBTN (" + reason + ")"
226+
}
227+
} else if rule == peerIP {
228+
return true, -1, "Bad-IP_FromBTN (" + reason + ")"
229+
}
230+
}
231+
}
232+
for reason, rules := range btnRules.Port {
233+
for _, rule := range rules {
234+
if rule == peerPortStr || rule == "ALL" {
235+
return true, peerPort, "Bad-IP_FromBTN (" + reason + ")"
236+
}
237+
}
238+
}
239+
for reason, rules := range btnRules.PeerID {
240+
for _, rule := range rules {
241+
if BTN_MatchEntry(peerID, rule) {
242+
return true, peerPort, "Bad-IP_FromBTN (" + reason + ")"
243+
}
244+
}
245+
}
246+
for reason, rules := range btnRules.ClientName {
247+
for _, rule := range rules {
248+
if BTN_MatchEntry(peerClient, rule) {
249+
return true, peerPort, "Bad-IP_FromBTN (" + reason + ")"
250+
}
251+
}
252+
}
253+
254+
return false, 0, ""
255+
}
134256

135257
func BTN_GetConfig() {
136258
if config.BTNConfigureURL == "" || (atomic.LoadInt64(&btn_lastGetConfig)+int64(btn_configureInterval)) > atomic.LoadInt64(&currentTimestamp) {

SyncServer.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,19 @@ type SyncServer_SubmitStruct struct {
2020
TorrentMap map[string]TorrentInfoStruct `json:"torrentMap"`
2121
}
2222

23+
type SyncServer_RuleStruct struct {
24+
Net *net.IPNet
25+
Reason string
26+
}
27+
2328
var syncServer_isSubmiting atomic.Bool
2429
var syncServer_lastSync int64 = 0
2530
var syncServer_syncConfig = SyncServer_ConfigStruct{
2631
Interval: 60,
2732
Status: "",
2833
BlockIPRule: make(map[string][]string),
2934
}
30-
var ipBlockCIDRMapFromSyncServerCompiled = make(map[string]*net.IPNet)
35+
var syncServer_CompiledRules []SyncServer_RuleStruct
3136
var ipBlockCIDRMapMutex sync.RWMutex
3237

3338
func SyncWithServer_PrepareJSON(torrentMap map[string]TorrentInfoStruct) (bool, string) {
@@ -64,7 +69,7 @@ func SyncWithServer_Submit(syncJSON string) bool {
6469
return false
6570
}
6671

67-
tmpIPBlockCIDRMapFromSyncServerCompiled := make(map[string]*net.IPNet)
72+
var tmpSyncServerCompiledRules []SyncServer_RuleStruct
6873

6974
for reason, ipArr := range syncServer_syncConfig.BlockIPRule {
7075
logReason := false
@@ -76,11 +81,6 @@ func SyncWithServer_Submit(syncJSON string) bool {
7681
continue
7782
}
7883

79-
if cidr, exists := ipBlockCIDRMapFromSyncServerCompiled[ipBlockListLine]; exists {
80-
tmpIPBlockCIDRMapFromSyncServerCompiled[ipBlockListLine] = cidr
81-
continue
82-
}
83-
8484
Log("Debug-SyncWithServer_Compile", ":%d %s", false, ipBlockListLineNum, ipBlockListLine)
8585
cidr := ParseIPCIDR(ipBlockListLine)
8686
if cidr == nil {
@@ -93,18 +93,35 @@ func SyncWithServer_Submit(syncJSON string) bool {
9393
Log("SyncWithServer", GetLangText("SyncWithServer_Compile-BlockByReason"), true, reason)
9494
}
9595

96-
tmpIPBlockCIDRMapFromSyncServerCompiled[ipBlockListLine] = cidr
96+
tmpSyncServerCompiledRules = append(tmpSyncServerCompiledRules, SyncServer_RuleStruct{Net: cidr, Reason: reason})
9797
Log("SyncWithServer_BlockCIDR", ":%d %s", false, ipBlockListLineNum, ipBlockListLine)
9898
}
9999
}
100100

101101
ipBlockCIDRMapMutex.Lock()
102-
ipBlockCIDRMapFromSyncServerCompiled = tmpIPBlockCIDRMapFromSyncServerCompiled
102+
syncServer_CompiledRules = tmpSyncServerCompiledRules
103103
ipBlockCIDRMapMutex.Unlock()
104104

105-
Log("Debug-SyncWithServer", GetLangText("Success-SyncWithServer"), true, len(ipBlockCIDRMapFromSyncServerCompiled))
105+
Log("Debug-SyncWithServer", GetLangText("Success-SyncWithServer"), true, len(syncServer_CompiledRules))
106106
return true
107107
}
108+
109+
func SyncServer_CheckPeer(ipObj net.IP) (bool, string) {
110+
if ipObj == nil {
111+
return false, ""
112+
}
113+
114+
ipBlockCIDRMapMutex.RLock()
115+
defer ipBlockCIDRMapMutex.RUnlock()
116+
117+
for _, rule := range syncServer_CompiledRules {
118+
if rule.Net != nil && rule.Net.Contains(ipObj) {
119+
return true, "Bad-IP_FromSyncServer (" + rule.Reason + ")"
120+
}
121+
}
122+
123+
return false, ""
124+
}
108125
func SyncWithServer_FullSubmit(syncJSON string) bool {
109126
syncStatus := SyncWithServer_Submit(syncJSON)
110127
syncServer_isSubmiting.Store(false)
Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ func TestSyncWithServerSubmitCompilesCIDRs(t *testing.T) {
5656
oldClientExternal := httpClientExternal
5757
oldConfig := config
5858
oldSyncConfig := syncServer_syncConfig
59-
oldCIDRMap := ipBlockCIDRMapFromSyncServerCompiled
59+
oldRules := syncServer_CompiledRules
6060
defer func() {
6161
httpClientExternal = oldClientExternal
6262
config = oldConfig
6363
syncServer_syncConfig = oldSyncConfig
64-
ipBlockCIDRMapFromSyncServerCompiled = oldCIDRMap
64+
syncServer_CompiledRules = oldRules
6565
}()
6666

6767
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -84,21 +84,54 @@ func TestSyncWithServerSubmitCompilesCIDRs(t *testing.T) {
8484
Status: "",
8585
BlockIPRule: map[string][]string{},
8686
}
87-
ipBlockCIDRMapFromSyncServerCompiled = map[string]*net.IPNet{}
87+
syncServer_CompiledRules = []SyncServer_RuleStruct{}
8888

8989
if !SyncWithServer_Submit(`{"dummy":true}`) {
9090
t.Fatal("SyncWithServer_Submit should succeed")
9191
}
9292
if syncServer_syncConfig.Interval != 90 {
9393
t.Fatalf("Interval=%d, want 90", syncServer_syncConfig.Interval)
9494
}
95-
if len(ipBlockCIDRMapFromSyncServerCompiled) != 2 {
96-
t.Fatalf("compiled CIDR count=%d, want 2", len(ipBlockCIDRMapFromSyncServerCompiled))
95+
if len(syncServer_CompiledRules) != 2 {
96+
t.Fatalf("compiled Rule count=%d, want 2", len(syncServer_CompiledRules))
9797
}
98-
if _, ok := ipBlockCIDRMapFromSyncServerCompiled["1.2.3.4"]; !ok {
99-
t.Fatal("compiled CIDRs should contain IPv4 entry")
98+
99+
foundIPv4 := false
100+
foundIPv6 := false
101+
for _, rule := range syncServer_CompiledRules {
102+
if rule.Net.String() == "1.2.3.4/32" {
103+
foundIPv4 = true
104+
}
105+
if rule.Net.String() == "2001:db8::/64" {
106+
foundIPv6 = true
107+
}
108+
}
109+
if !foundIPv4 {
110+
t.Fatal("compiled Rules should contain IPv4 entry")
111+
}
112+
if !foundIPv6 {
113+
t.Fatal("compiled Rules should contain IPv6 entry")
114+
}
115+
}
116+
117+
func TestSyncServerCheckPeer(t *testing.T) {
118+
oldRules := syncServer_CompiledRules
119+
defer func() {
120+
syncServer_CompiledRules = oldRules
121+
}()
122+
123+
_, subnet, _ := net.ParseCIDR("10.0.0.0/24")
124+
syncServer_CompiledRules = []SyncServer_RuleStruct{
125+
{Net: subnet, Reason: "local-network"},
100126
}
101-
if _, ok := ipBlockCIDRMapFromSyncServerCompiled["2001:db8::/64"]; !ok {
102-
t.Fatal("compiled CIDRs should contain IPv6 entry")
127+
128+
ok, reason := SyncServer_CheckPeer(net.ParseIP("10.0.0.5"))
129+
if !ok || reason != "Bad-IP_FromSyncServer (local-network)" {
130+
t.Fatalf("SyncServer_CheckPeer(10.0.0.5) = (%v, %q), want (true, \"Bad-IP_FromSyncServer (local-network)\")", ok, reason)
131+
}
132+
133+
ok, _ = SyncServer_CheckPeer(net.ParseIP("10.0.1.5"))
134+
if ok {
135+
t.Fatal("SyncServer_CheckPeer(10.0.1.5) should be false")
103136
}
104137
}

console.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func Task() {
258258
return true
259259
})
260260

261-
if !config.IPUploadedCheck && iblcLen <= 0 && len(ipBlockCIDRMapFromSyncServerCompiled) <= 0 {
261+
if !config.IPUploadedCheck && iblcLen <= 0 && len(syncServer_CompiledRules) <= 0 {
262262
Log("Task", GetLangText("Task_BanInfo"), true, blockCount, len(blockPeerMap))
263263
} else {
264264
Log("Task", GetLangText("Task_BanInfoWithIP"), true, blockCount, ipBlockCount, len(blockPeerMap))

0 commit comments

Comments
 (0)