Skip to content

Commit ee787e5

Browse files
committed
feat: 添加ANSI颜色输出 + 移除弃用的rand.Seed + 支持强制退出
1 parent f09c095 commit ee787e5

5 files changed

Lines changed: 105 additions & 54 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ deadpool代理池工具,可从**hunter**、**quake**、**fofa**等**网络空
3737

3838
如图,同时开启了hunter、quake、fofa,lastData.txt中也放入了之前收集的代理,会根据config.toml中的配置信息做检测
3939

40+
![](images/new.jpg)
41+
42+
开启fofa、hunter、quake开关时,自动抓数据
43+
4044
![](images/init.png)
4145

46+
47+
4248
监听到请求后,会轮询收集的代理来转发
4349

4450
![](images/polling.png)

images/new.jpg

167 KB
Loading

main.go

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"io"
77
"log"
8-
"math/rand"
98
"net"
109
"os"
1110
"os/signal"
@@ -19,11 +18,8 @@ import (
1918
)
2019

2120
func main() {
22-
// 初始化随机种子
23-
rand.Seed(time.Now().UnixNano())
24-
2521
utils.Banner()
26-
fmt.Print("By:thinkoaa GitHub:https://github.com/thinkoaa/Deadpool\n\n\n")
22+
fmt.Print(utils.ColorCyan + "By:thinkoaa GitHub:https://github.com/thinkoaa/Deadpool\n" + utils.ColorReset + "\n")
2723

2824
// 解析命令行参数
2925
configPath := "config.toml"
@@ -49,19 +45,19 @@ func main() {
4945
}
5046

5147
if help {
52-
fmt.Println("Deadpool 代理池工具 使用帮助:")
53-
fmt.Println(" -h, --help 显示此帮助信息")
54-
fmt.Println(" -c, --config <path> 指定配置文件路径 (默认: config.toml)")
55-
fmt.Println(" -l, --lastdata <path> 指定lastdata文件路径 (默认: lastData.txt)")
56-
fmt.Println(" 使用此选项时,不会重新从网络空间获取代理")
48+
fmt.Println(utils.ColorCyan + "Deadpool 代理池工具 使用帮助:" + utils.ColorReset)
49+
fmt.Println(utils.ColorCyan + " -h, --help 显示此帮助信息" + utils.ColorReset)
50+
fmt.Println(utils.ColorCyan + " -c, --config <path> 指定配置文件路径 (默认: config.toml)" + utils.ColorReset)
51+
fmt.Println(utils.ColorCyan + " -l, --lastdata <path> 指定lastdata文件路径 (默认: lastData.txt)" + utils.ColorReset)
52+
fmt.Println(utils.ColorCyan + " 使用此选项时,不会重新从网络空间获取代理" + utils.ColorReset)
5753
os.Exit(0)
5854
}
5955

6056
// 读取配置文件
6157
config, err := utils.LoadConfig(configPath)
6258
if err != nil {
63-
fmt.Printf("配置文件 %s 存在错误: %v\n", configPath, err)
64-
fmt.Println("请检查配置文件格式是否正确,参考 README 中的配置说明")
59+
fmt.Printf(utils.ColorRed+"配置文件 %s 存在错误: %v\n"+utils.ColorReset, configPath, err)
60+
fmt.Println(utils.ColorRed + "请检查配置文件格式是否正确,参考 README 中的配置说明" + utils.ColorReset)
6561
os.Exit(1)
6662
}
6763

@@ -78,19 +74,19 @@ func main() {
7874

7975
// 从本地文件中取socks代理
8076
if utils.LogLevel == "debug" {
81-
fmt.Print("***debug模式: 每个请求的代理信息会打印到命令行***\n\n")
77+
fmt.Print(utils.ColorCyan + "***debug模式: 每个请求的代理信息会打印到命令行***\n" + utils.ColorReset + "\n")
8278
}
83-
fmt.Print("***直接使用fmt打印当前使用的代理,若高并发时,命令行打印可能会阻塞,不对打印做特殊处理,可忽略,不会影响实际的请求转发***\n\n")
79+
fmt.Print(utils.ColorYellow + "***直接使用fmt打印信息,基本上是打印异常的信息***\n" + utils.ColorReset + "\n")
8480
if lastDataPath == utils.LastDataFile {
8581
// 未指定自定义lastdata路径时,从网络空间获取代理
8682
utils.GetSocks(config)
8783
}
8884

8985
if len(utils.SocksList) == 0 {
90-
fmt.Println("未发现代理数据,请调整配置信息,或向" + utils.LastDataFile + "中直接写入IP:PORT格式的socks5代理\n程序退出")
86+
fmt.Print(utils.ColorRed + "未发现代理数据,请调整配置信息,或向" + utils.LastDataFile + "中直接写入IP:PORT格式的socks5代理\n程序退出" + utils.ColorReset + "\n")
9187
os.Exit(1)
9288
}
93-
fmt.Printf("根据IP:PORT去重后,共发现%v个代理\n检测可用性中......\n", len(utils.SocksList))
89+
fmt.Printf(utils.ColorCyan+"根据IP:PORT去重后,共发现%v个代理\n检测可用性中......\n"+utils.ColorReset, len(utils.SocksList))
9490

9591
//开始检测代理存活性
9692

@@ -103,27 +99,27 @@ func main() {
10399
if periodicChecking != "" {
104100
cronFlag = true
105101
cron.AddFunc(periodicChecking, func() {
106-
fmt.Printf("\n===代理存活自检 开始===\n\n")
102+
fmt.Printf(utils.ColorBlue + "\n===代理存活自检 开始===\n\n" + utils.ColorReset)
107103
tempList := make([]string, len(utils.EffectiveList))
108104
copy(tempList, utils.EffectiveList)
109105
utils.CheckSocks(config.CheckSocks, tempList)
110-
fmt.Printf("\n===代理存活自检 结束===\n\n")
106+
fmt.Printf(utils.ColorBlue + "\n===代理存活自检 结束===\n\n" + utils.ColorReset)
111107
})
112108
}
113109
//根据配置信息,周期性取本地以及hunter、quake、fofa的数据
114110
periodicGetSocks := strings.TrimSpace(config.Task.PeriodicGetSocks)
115111
if periodicGetSocks != "" {
116112
cronFlag = true
117113
cron.AddFunc(periodicGetSocks, func() {
118-
fmt.Printf("\n===周期性取代理数据 开始===\n\n")
114+
fmt.Printf(utils.ColorBlue + "\n===周期性取代理数据 开始===\n\n" + utils.ColorReset)
119115
utils.SocksList = utils.SocksList[:0]
120116
utils.GetSocks(config)
121-
fmt.Printf("根据IP:PORT去重后,共发现%v个代理\n检测可用性中......\n", len(utils.SocksList))
117+
fmt.Printf(utils.ColorCyan+"根据IP:PORT去重后,共发现%v个代理\n检测可用性中......\n"+utils.ColorReset, len(utils.SocksList))
122118
utils.CheckSocks(config.CheckSocks, utils.SocksList)
123119
if len(utils.EffectiveList) != 0 {
124120
utils.WriteLinesToFile() //存活代理写入硬盘,以备下次启动直接读取
125121
}
126-
fmt.Printf("\n===周期性取代理数据 结束===\n\n")
122+
fmt.Printf(utils.ColorBlue + "\n===周期性取代理数据 结束===\n\n" + utils.ColorReset)
127123

128124
})
129125
}
@@ -133,7 +129,7 @@ func main() {
133129
}
134130

135131
if len(utils.EffectiveList) == 0 {
136-
fmt.Println("根据规则检测后,未发现满足要求的代理,请调整配置,程序退出")
132+
fmt.Println(utils.ColorRed + "根据规则检测后,未发现满足要求的代理,请调整配置,程序退出" + utils.ColorReset)
137133
os.Exit(1)
138134
}
139135

@@ -154,13 +150,13 @@ func main() {
154150
}
155151
server, _ := socks5.New(conf)
156152
listenerAddr := config.Listener.IP + ":" + strconv.Itoa(config.Listener.Port)
157-
fmt.Printf("======其他工具通过配置 socks5://%v 使用收集的代理,如有账号密码,记得配置======\n", listenerAddr)
158-
fmt.Println("按回车键随机切换到下一个代理IP,输入 s 回车查看统计...")
153+
fmt.Printf(utils.ColorGreen+"======其他工具通过配置 socks5://%v 使用收集的代理,如有账号密码,记得配置======\n"+utils.ColorReset, listenerAddr)
154+
fmt.Println(utils.ColorYellow + "按回车键随机切换到下一个代理IP,输入 s 回车查看统计..." + utils.ColorReset)
159155

160156
// 手动创建 listener,支持优雅关闭
161157
l, err := net.Listen("tcp", listenerAddr)
162158
if err != nil {
163-
fmt.Printf("本地监听服务启动失败:%v\n", err)
159+
fmt.Printf(utils.ColorRed+"本地监听服务启动失败:%v\n"+utils.ColorReset, err)
164160
os.Exit(1)
165161
}
166162

@@ -169,7 +165,8 @@ func main() {
169165
sigChan := make(chan os.Signal, 1)
170166
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
171167
<-sigChan
172-
fmt.Println("\n\n[优雅关闭] 收到关闭信号,准备退出...")
168+
fmt.Println(utils.ColorCyan + "\n\n[优雅关闭] 收到关闭信号,准备退出..." + utils.ColorReset)
169+
fmt.Println(utils.ColorYellow + "[提示] 再次按 Ctrl+C 可强制退出" + utils.ColorReset)
173170
// 关闭 ShutdownChan,通知拒绝新连接
174171
select {
175172
case <-utils.ShutdownChan:
@@ -185,16 +182,20 @@ func main() {
185182
timeout := time.After(30 * time.Second)
186183
for {
187184
select {
185+
case <-sigChan:
186+
// 再次收到关闭信号,强制退出
187+
fmt.Println(utils.ColorRed + "\n[优雅关闭] 收到强制退出信号,立即退出!" + utils.ColorReset)
188+
os.Exit(0)
188189
case <-timeout:
189-
fmt.Println("[优雅关闭] 等待超时,强制退出")
190+
fmt.Println(utils.ColorYellow + "[优雅关闭] 等待超时,强制退出" + utils.ColorReset)
190191
os.Exit(0)
191192
default:
192193
active := utils.GetActiveConns()
193194
if active == 0 {
194-
fmt.Println("[优雅关闭] 所有连接已完成,退出。")
195+
fmt.Println(utils.ColorGreen + "[优雅关闭] 所有连接已完成,退出。" + utils.ColorReset)
195196
os.Exit(0)
196197
}
197-
fmt.Printf("[优雅关闭] 等待 %d 个活跃连接完成...\n", active)
198+
fmt.Printf(utils.ColorCyan+"[优雅关闭] 等待 %d 个活跃连接完成...\n"+utils.ColorReset, active)
198199
time.Sleep(1 * time.Second)
199200
}
200201
}
@@ -208,17 +209,17 @@ func main() {
208209
input = strings.TrimSpace(input)
209210
if input == "s" || input == "S" {
210211
utils.PrintStats()
211-
fmt.Println("按回车键随机切换到下一个代理IP,输入 s 回车查看统计...")
212+
fmt.Println(utils.ColorYellow + "按回车键随机切换到下一个代理IP,输入 s 回车查看统计..." + utils.ColorReset)
212213
continue
213214
}
214215
utils.SetNextProxyIndex()
215216
currentIndex := utils.GetCurrentProxyIndex()
216217
if currentIndex >= 0 && len(utils.EffectiveList) > 0 {
217-
fmt.Printf("已随机切换到代理IP: %s (剩余可用: %d)\n", utils.EffectiveList[currentIndex], len(utils.EffectiveList))
218+
fmt.Printf(utils.ColorGreen+"已随机切换到代理IP: %s (剩余可用: %d)\n"+utils.ColorReset, utils.EffectiveList[currentIndex], len(utils.EffectiveList))
218219
} else {
219-
fmt.Println("没有可用的代理IP")
220+
fmt.Println(utils.ColorRed + "没有可用的代理IP" + utils.ColorReset)
220221
}
221-
fmt.Println("按回车键随机切换到下一个代理IP,输入 s 回车查看统计...")
222+
fmt.Println(utils.ColorYellow + "按回车键随机切换到下一个代理IP,输入 s 回车查看统计..." + utils.ColorReset)
222223
}
223224
}()
224225

@@ -231,7 +232,7 @@ func main() {
231232
// 主 goroutine 阻塞等待(信号处理 goroutine 会调用 os.Exit)
232233
select {}
233234
default:
234-
fmt.Printf("SOCKS5 服务异常: %v\n", err)
235+
fmt.Printf(utils.ColorRed+"SOCKS5 服务异常: %v\n"+utils.ColorReset, err)
235236
os.Exit(1)
236237
}
237238
}

utils/globals.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package utils
22

33
import (
4+
"fmt"
45
"math/rand"
56
"sync"
67
"time"
@@ -73,5 +74,5 @@ func Banner() {
7374
\ \_\
7475
\/_/
7576
`
76-
print(banner)
77+
fmt.Print(ColorCyan + banner + ColorReset)
7778
}

utils/utils.go

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ import (
2020
"golang.org/x/net/proxy"
2121
)
2222

23+
// 颜色常量 (ANSI escape codes)
24+
const (
25+
ColorReset = "\033[0m"
26+
ColorRed = "\033[31m"
27+
ColorGreen = "\033[32m"
28+
ColorYellow = "\033[33m"
29+
ColorCyan = "\033[36m"
30+
ColorBlue = "\033[34m"
31+
ColorWhite = "\033[37m"
32+
ColorGray = "\033[90m"
33+
)
34+
2335
// InitProxyStats 初始化/更新代理统计信息(新增代理时调用,线程安全)
2436
func InitProxyStats(proxies []string) {
2537
mu.Lock()
@@ -131,28 +143,58 @@ type ProxyStatsItem struct {
131143
LastUsed time.Time
132144
}
133145

134-
// PrintStats 打印所有代理的统计信息
146+
// PrintStats 打印所有代理的统计信息(英文表头+颜色)
135147
func PrintStats() {
136148
items := GetSortedProxyStats()
137149
if len(items) == 0 {
138-
fmt.Println("\n[统计] 暂无代理统计数据")
150+
fmt.Println(ColorCyan + "\n[Stats] No proxy statistics available" + ColorReset)
139151
return
140152
}
141-
fmt.Println("\n" + strings.Repeat("=", 90))
142-
fmt.Printf(" 代理统计信息 (共 %d 个)\n", len(items))
143-
fmt.Println(strings.Repeat("=", 90))
144-
fmt.Printf(" %-25s %6s %6s %6s %7s %10s %6s\n",
145-
"代理地址", "使用数", "成功数", "失败数", "成功率", "平均响应", "连败")
146-
fmt.Println(strings.Repeat("-", 80))
153+
fmt.Println("\n" + ColorBlue + strings.Repeat("=", 90) + ColorReset)
154+
fmt.Printf(ColorCyan+" Proxy Stats (total: %d)\n"+ColorReset, len(items))
155+
fmt.Println(ColorBlue + strings.Repeat("=", 90) + ColorReset)
156+
// 英文表头,对齐不会出问题
157+
fmt.Printf(" %-25s %6s %6s %6s %7s %9s %6s\n",
158+
"ADDR", "USES", "OK", "FAIL", "RATE", "AVG(ms)", "STREAK")
159+
fmt.Println(ColorGray + strings.Repeat("-", 80) + ColorReset)
147160
for _, item := range items {
148161
if item.UseCount == 0 {
149162
continue
150163
}
151-
fmt.Printf(" %-25s %6d %6d %6d %6.1f%% %7dms %5d\n",
164+
// 成功率颜色
165+
rateColor := ColorGreen
166+
if item.SuccessRate < 90 {
167+
rateColor = ColorYellow
168+
}
169+
if item.SuccessRate < 50 {
170+
rateColor = ColorRed
171+
}
172+
// 响应时间颜色
173+
timeColor := ColorGreen
174+
if item.AvgRespTime > 500 {
175+
timeColor = ColorYellow
176+
}
177+
if item.AvgRespTime > 1000 {
178+
timeColor = ColorRed
179+
}
180+
// 连败颜色
181+
streakColor := ColorGreen
182+
if item.FailStreak > 0 {
183+
streakColor = ColorYellow
184+
}
185+
if item.FailStreak >= GetMaxFailCount() {
186+
streakColor = ColorRed
187+
}
188+
fmt.Printf(" %-25s %6d %6d %6d "+rateColor+"%6.1f%%"+ColorReset+" "+timeColor+"%7dms"+ColorReset+" "+streakColor+"%5d"+ColorReset+"\n",
152189
item.Addr, item.UseCount, item.SuccessCount, item.FailCount,
153190
item.SuccessRate, item.AvgRespTime, item.FailStreak)
154191
}
155-
fmt.Println(strings.Repeat("=", 90))
192+
fmt.Println(ColorBlue + strings.Repeat("=", 90) + ColorReset)
193+
}
194+
195+
// GetMaxFailCount 导出最大失败次数(供PrintStats使用)
196+
func GetMaxFailCount() int {
197+
return getMaxFailCount()
156198
}
157199

158200
// IncrActiveConns 增加活跃连接计数
@@ -251,7 +293,7 @@ func CheckSocks(checkSocks CheckSocksConfig, socksListParam []string) {
251293
isOpenGeolocateSwitch = true
252294
reqUrl = checkGeolocateConfig.CheckURL
253295
}
254-
fmt.Printf("时间:[ %v ] 并发:[ %v ],超时标准:[ %vs ]\n", time.Now().Format("2006-01-02 15:04:05"), maxConcurrentReq, timeout)
296+
fmt.Printf(ColorCyan+"时间:[ %v ] 并发:[ %v ],超时标准:[ %vs ]\n"+ColorReset, time.Now().Format("2006-01-02 15:04:05"), maxConcurrentReq, timeout)
255297
var num int
256298
total := len(socksListParam)
257299
var tmpEffectiveList []string
@@ -263,7 +305,7 @@ func CheckSocks(checkSocks CheckSocksConfig, socksListParam []string) {
263305
go func(proxyAddr string) {
264306
tmpMu.Lock()
265307
num++
266-
fmt.Printf("\r正检测第 [ %v/%v ] 个代理,异步处理中... ", num, total)
308+
fmt.Printf(ColorCyan+"\r正检测第 [ %v/%v ] 个代理,异步处理中... "+ColorReset, num, total)
267309
tmpMu.Unlock()
268310
defer Wg.Done()
269311
defer func() {
@@ -341,7 +383,7 @@ func CheckSocks(checkSocks CheckSocksConfig, socksListParam []string) {
341383
if sec == 0 {
342384
sec = 1
343385
}
344-
fmt.Printf("\n根据配置规则检测完成,用时 [ %vs ] ,共发现 [ %v ] 个可用\n", sec, len(tmpEffectiveList))
386+
fmt.Printf(ColorGreen+"\n根据配置规则检测完成,用时 [ %vs ] ,共发现 [ %v ] 个可用\n"+ColorReset, sec, len(tmpEffectiveList))
345387
}
346388

347389
func WriteLinesToFile() error {
@@ -381,7 +423,8 @@ func transmitReqFromClient(network string, address string) (net.Conn, error) {
381423
for {
382424
tempProxy := getNextProxy()
383425
if tempProxy == "" {
384-
return nil, fmt.Errorf("已无可用代理,请重新获取代理并运行程序")
426+
fmt.Println(ColorRed + "[错误] 已无可用代理,请重新获取代理并运行程序" + ColorReset)
427+
return nil, fmt.Errorf("no available proxy")
385428
}
386429
// 根据日志级别决定是否打印当前使用的代理
387430
if LogLevel == "debug" {
@@ -398,18 +441,18 @@ func transmitReqFromClient(network string, address string) (net.Conn, error) {
398441
if err != nil {
399442
// delInvalidProxy 内部原子化记录失败并判断是否移除
400443
if delInvalidProxy(tempProxy) {
401-
fmt.Printf("[%s] 代理 %s 连续失败已达上限,已移除,自动切换下一个...\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy)
444+
fmt.Printf(ColorYellow+"[%s] 代理 %s 连续失败已达上限,已移除,自动切换下一个..."+ColorReset+"\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy)
402445
} else {
403-
fmt.Printf("[%s] 代理 %s 连接失败,连续失败 %d/%d\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy, getFailStreak(tempProxy), getMaxFailCount())
446+
fmt.Printf(ColorYellow+"[%s] 代理 %s 连接失败,连续失败 %d/%d"+ColorReset+"\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy, getFailStreak(tempProxy), getMaxFailCount())
404447
}
405448
continue
406449
}
407450
conn, err := dialect.Dial(network, address)
408451
if err != nil {
409452
if delInvalidProxy(tempProxy) {
410-
fmt.Printf("[%s] 代理 %s 连接目标失败已达上限,已移除,自动切换下一个...\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy)
453+
fmt.Printf(ColorYellow+"[%s] 代理 %s 连接目标失败已达上限,已移除,自动切换下一个..."+ColorReset+"\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy)
411454
} else {
412-
fmt.Printf("[%s] 代理 %s 连接目标失败,连续失败 %d/%d\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy, getFailStreak(tempProxy), getMaxFailCount())
455+
fmt.Printf(ColorYellow+"[%s] 代理 %s 连接目标失败,连续失败 %d/%d"+ColorReset+"\n", time.Now().Format("2006-01-02 15:04:05"), tempProxy, getFailStreak(tempProxy), getMaxFailCount())
413456
}
414457
continue
415458
}
@@ -459,7 +502,7 @@ func getNextProxy() string {
459502
return "" // 返回空字符串,由调用方处理
460503
}
461504
if len(EffectiveList) <= 2 {
462-
fmt.Printf("***可用代理已仅剩%v个,%v,***\n", len(EffectiveList), EffectiveList)
505+
fmt.Printf(ColorYellow+"***可用代理已仅剩%v个,%v,***"+ColorReset+"\n", len(EffectiveList), EffectiveList)
463506
}
464507
// 随机选择一个代理,避免短时间内重复
465508
return EffectiveList[rand.Intn(len(EffectiveList))]

0 commit comments

Comments
 (0)