19 type ScanConfig
struct {
22 HTTPVerifyHosts
[]string
23 VerifyCommonName
string
26 HandshakeTimeout time
.Duration
27 ScanMinRTT time
.Duration
28 ScanMaxRTT time
.Duration
32 OutputSeparator
string
36 type GScanConfig
struct {
39 ScanMinPingRTT time
.Duration
40 ScanMaxPingRTT time
.Duration
53 rand
.Seed(time
.Now().Unix())
55 log
.SetFlags(log
.LstdFlags | log
.Lshortfile
)
58 func initConfig(cfgfile
, execFolder
string) *GScanConfig
{
59 if strings
.HasPrefix(cfgfile
, "./") {
60 cfgfile
= filepath
.Join(execFolder
, cfgfile
)
63 gcfg
:= new(GScanConfig
)
64 if err
:= readJsonConfig(cfgfile
, gcfg
); err
!= nil {
68 if gcfg
.EnableBackup
{
69 if strings
.HasPrefix(gcfg
.BackupDir
, "./") {
70 gcfg
.BackupDir
= filepath
.Join(execFolder
, gcfg
.BackupDir
)
72 if _
, err
:= os
.Stat(gcfg
.BackupDir
); os
.IsNotExist(err
) {
73 if err
:= os
.MkdirAll(gcfg
.BackupDir
, 0755); err
!= nil {
79 gcfg
.ScanMode
= strings
.ToLower(gcfg
.ScanMode
)
80 if gcfg
.ScanMode
== "ping" {
81 gcfg
.VerifyPing
= false
84 gcfg
.ScanMinPingRTT
= gcfg
.ScanMinPingRTT
* time
.Millisecond
85 gcfg
.ScanMaxPingRTT
= gcfg
.ScanMaxPingRTT
* time
.Millisecond
87 cfgs
:= []*ScanConfig
{&gcfg
.Quic
, &gcfg
.Tls
, &gcfg
.Sni
, &gcfg
.Ping
}
88 for _
, c
:= range cfgs
{
89 if strings
.HasPrefix(c
.InputFile
, "./") {
90 c
.InputFile
= filepath
.Join(execFolder
, c
.InputFile
)
92 c
.InputFile
, _
= filepath
.Abs(c
.InputFile
)
94 if strings
.HasPrefix(c
.OutputFile
, "./") {
95 c
.OutputFile
= filepath
.Join(execFolder
, c
.OutputFile
)
97 c
.OutputFile
, _
= filepath
.Abs(c
.OutputFile
)
99 if _
, err
:= os
.Stat(c
.InputFile
); os
.IsNotExist(err
) {
100 os
.OpenFile(c
.InputFile
, os
.O_CREATE|os
.O_TRUNC|os
.O_RDWR
, 0644)
103 c
.ScanMinRTT
*= time
.Millisecond
104 c
.ScanMaxRTT
*= time
.Millisecond
105 c
.HandshakeTimeout
*= time
.Millisecond
111 var disablePause
bool
113 if r
:= recover(); r
!= nil {
114 fmt
.Println("panic:", r
)
118 if runtime
.GOOS
== "windows" {
119 cmd
:= exec
.Command("cmd", "/C", "pause")
120 cmd
.Stdout
= os
.Stdout
122 // 改为 start, 程序可以正常退出, 这样一些程序监视工具可以正常测到程序结束了
125 fmt
.Println("Press [Enter] to exit...")
132 flag
.StringVar(&cfgfile
, "Config File", "./config.json", "Config file, json format")
135 var execFolder
= "./"
136 if e
, err
:= os
.Executable(); err
!= nil {
139 execFolder
= filepath
.Dir(e
)
143 gcfg
:= initConfig(cfgfile
, execFolder
)
144 disablePause
= gcfg
.DisablePause
147 scanMode
:= gcfg
.ScanMode
151 testIPFunc
= testQuic
160 testIPFunc
= testPing
162 // testIPFunc = testSocks5
166 iprangeFile
:= cfg
.InputFile
167 if _
, err
:= os
.Stat(iprangeFile
); os
.IsNotExist(err
) {
171 srs
:= &ScanRecords
{}
173 log
.Printf("Start loading IP Range file: %s\n", iprangeFile
)
174 ipqueue
, err
:= parseIPRangeFile(iprangeFile
)
179 log
.Printf("Start scanning available IP\n")
180 startTime
:= time
.Now()
181 StartScan(srs
, gcfg
, cfg
, ipqueue
)
182 log
.Printf("Scanned %d IP in %s, found %d records\n", srs
.ScanCount(), time
.Since(startTime
).String(), len(srs
.records
))
184 if records
:= srs
.records
; len(records
) > 0 {
185 sort
.Slice(records
, func(i
, j
int) bool {
186 return records
[i
].RTT
< records
[j
].RTT
188 a
:= make([]string, len(records
))
189 for i
, r
:= range records
{
192 b
:= new(bytes
.Buffer
)
193 if cfg
.OutputSeparator
== "gop" {
194 out
:= strings
.Join(a
, `", "`)
195 b
.WriteString(`"` + out
+ `",`)
197 out
:= strings
.Join(a
, cfg
.OutputSeparator
)
201 if err
:= ioutil
.WriteFile(cfg
.OutputFile
, b
.Bytes(), 0644); err
!= nil {
202 log
.Printf("Failed to write output file:%s for reason:%v\n", cfg
.OutputFile
, err
)
204 log
.Printf("All results writed to %s\n", cfg
.OutputFile
)
206 if gcfg
.EnableBackup
{
207 filename
:= fmt
.Sprintf("%s_%s_lv%d.txt", scanMode
, time
.Now().Format("20060102_150405"), cfg
.Level
)
208 bakfilename
:= filepath
.Join(gcfg
.BackupDir
, filename
)
209 if err
:= ioutil
.WriteFile(bakfilename
, b
.Bytes(), 0644); err
!= nil {
210 log
.Printf("Failed to write output file:%s for reason:%v\n", bakfilename
, err
)
212 log
.Printf("All results writed to %s\n", bakfilename
)