19 type ScanConfig
struct {
22 HTTPVerifyHosts
[]string
23 VerifyCommonName
[]string
24 HandshakeTimeout time
.Duration
25 ScanMinRTT time
.Duration
26 ScanMaxRTT time
.Duration
30 OutputSeparator
string
34 type GScanConfig
struct {
37 ScanMinPingRTT time
.Duration
38 ScanMaxPingRTT time
.Duration
51 rand
.Seed(time
.Now().Unix())
53 log
.SetFlags(log
.LstdFlags | log
.Lshortfile
)
56 func initConfig(cfgfile
, execFolder
string) *GScanConfig
{
57 if strings
.HasPrefix(cfgfile
, "./") {
58 cfgfile
= filepath
.Join(execFolder
, cfgfile
)
61 gcfg
:= new(GScanConfig
)
62 if err
:= readJsonConfig(cfgfile
, gcfg
); err
!= nil {
66 if gcfg
.EnableBackup
{
67 if strings
.HasPrefix(gcfg
.BackupDir
, "./") {
68 gcfg
.BackupDir
= filepath
.Join(execFolder
, gcfg
.BackupDir
)
70 if _
, err
:= os
.Stat(gcfg
.BackupDir
); os
.IsNotExist(err
) {
71 if err
:= os
.MkdirAll(gcfg
.BackupDir
, 0755); err
!= nil {
77 gcfg
.ScanMode
= strings
.ToLower(gcfg
.ScanMode
)
78 if gcfg
.ScanMode
== "ping" {
79 gcfg
.VerifyPing
= false
82 gcfg
.ScanMinPingRTT
= gcfg
.ScanMinPingRTT
* time
.Millisecond
83 gcfg
.ScanMaxPingRTT
= gcfg
.ScanMaxPingRTT
* time
.Millisecond
85 cfgs
:= []*ScanConfig
{&gcfg
.Quic
, &gcfg
.Tls
, &gcfg
.Sni
, &gcfg
.Ping
}
86 for _
, c
:= range cfgs
{
87 if strings
.HasPrefix(c
.InputFile
, "./") {
88 c
.InputFile
= filepath
.Join(execFolder
, c
.InputFile
)
90 c
.InputFile
, _
= filepath
.Abs(c
.InputFile
)
92 if strings
.HasPrefix(c
.OutputFile
, "./") {
93 c
.OutputFile
= filepath
.Join(execFolder
, c
.OutputFile
)
95 c
.OutputFile
, _
= filepath
.Abs(c
.OutputFile
)
97 if _
, err
:= os
.Stat(c
.InputFile
); os
.IsNotExist(err
) {
98 os
.OpenFile(c
.InputFile
, os
.O_CREATE|os
.O_TRUNC|os
.O_RDWR
, 0644)
101 c
.ScanMinRTT
*= time
.Millisecond
102 c
.ScanMaxRTT
*= time
.Millisecond
103 c
.HandshakeTimeout
*= time
.Millisecond
109 var disablePause
bool
111 if r
:= recover(); r
!= nil {
112 fmt
.Println("panic:", r
)
116 if runtime
.GOOS
== "windows" {
117 cmd
:= exec
.Command("cmd", "/C", "pause")
118 cmd
.Stdout
= os
.Stdout
120 // 改为 start, 程序可以正常退出, 这样一些程序监视工具可以正常测到程序结束了
123 fmt
.Println("Press [Enter] to exit...")
130 flag
.StringVar(&cfgfile
, "Config File", "./config.json", "Config file, json format")
133 var execFolder
= "./"
134 if e
, err
:= os
.Executable(); err
!= nil {
137 execFolder
= filepath
.Dir(e
)
141 gcfg
:= initConfig(cfgfile
, execFolder
)
142 disablePause
= gcfg
.DisablePause
145 scanMode
:= gcfg
.ScanMode
149 testIPFunc
= testQuic
158 testIPFunc
= testPing
160 // testIPFunc = testSocks5
164 iprangeFile
:= cfg
.InputFile
165 if _
, err
:= os
.Stat(iprangeFile
); os
.IsNotExist(err
) {
169 srs
:= &ScanRecords
{}
171 log
.Printf("Start loading IP Range file: %s\n", iprangeFile
)
172 ipqueue
, err
:= parseIPRangeFile(iprangeFile
)
177 log
.Printf("Start scanning available IP\n")
178 startTime
:= time
.Now()
179 StartScan(srs
, gcfg
, cfg
, ipqueue
)
180 log
.Printf("Scanned %d IP in %s, found %d records\n", srs
.ScanCount(), time
.Since(startTime
).String(), len(srs
.records
))
182 if records
:= srs
.records
; len(records
) > 0 {
183 sort
.Slice(records
, func(i
, j
int) bool {
184 return records
[i
].RTT
< records
[j
].RTT
186 a
:= make([]string, len(records
))
187 for i
, r
:= range records
{
190 b
:= new(bytes
.Buffer
)
191 if cfg
.OutputSeparator
== "gop" {
192 out
:= strings
.Join(a
, `", "`)
193 b
.WriteString(`"` + out
+ `",`)
195 out
:= strings
.Join(a
, cfg
.OutputSeparator
)
199 if err
:= ioutil
.WriteFile(cfg
.OutputFile
, b
.Bytes(), 0644); err
!= nil {
200 log
.Printf("Failed to write output file:%s for reason:%v\n", cfg
.OutputFile
, err
)
202 log
.Printf("All results writed to %s\n", cfg
.OutputFile
)
204 if gcfg
.EnableBackup
{
205 filename
:= fmt
.Sprintf("%s_%s_lv%d.txt", scanMode
, time
.Now().Format("20060102_150405"), cfg
.Level
)
206 bakfilename
:= filepath
.Join(gcfg
.BackupDir
, filename
)
207 if err
:= ioutil
.WriteFile(bakfilename
, b
.Bytes(), 0644); err
!= nil {
208 log
.Printf("Failed to write output file:%s for reason:%v\n", bakfilename
, err
)
210 log
.Printf("All results writed to %s\n", bakfilename
)