diff VerifyCommonName
[gscan_quic.git] / gscan.go
blob2b142165671bda4e01168d5f6e74a75ea8dda05d
1 package main
3 import (
4 "bytes"
5 "flag"
6 "fmt"
7 "io/ioutil"
8 "log"
9 "math/rand"
10 "os"
11 "os/exec"
12 "path/filepath"
13 "runtime"
14 "sort"
15 "strings"
16 "time"
19 type ScanConfig struct {
20 ScanCountPerIP int
21 ServerName []string
22 HTTPVerifyHosts []string
23 VerifyCommonName []string
24 HandshakeTimeout time.Duration
25 ScanMinRTT time.Duration
26 ScanMaxRTT time.Duration
27 RecordLimit int
28 InputFile string
29 OutputFile string
30 OutputSeparator string
31 Level int
34 type GScanConfig struct {
35 ScanWorker int
36 VerifyPing bool
37 ScanMinPingRTT time.Duration
38 ScanMaxPingRTT time.Duration
39 DisablePause bool
40 EnableBackup bool
41 BackupDir string
43 ScanMode string
44 Ping ScanConfig
45 Quic ScanConfig
46 Tls ScanConfig
47 Sni ScanConfig
50 func init() {
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 {
63 log.Panicln(err)
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 {
72 log.Println(err)
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)
89 } else {
90 c.InputFile, _ = filepath.Abs(c.InputFile)
92 if strings.HasPrefix(c.OutputFile, "./") {
93 c.OutputFile = filepath.Join(execFolder, c.OutputFile)
94 } else {
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
105 return gcfg
108 func main() {
109 var disablePause bool
110 defer func() {
111 if r := recover(); r != nil {
112 fmt.Println("panic:", r)
114 fmt.Println()
115 if !disablePause {
116 if runtime.GOOS == "windows" {
117 cmd := exec.Command("cmd", "/C", "pause")
118 cmd.Stdout = os.Stdout
119 cmd.Stdin = os.Stdin
120 // 改为 start, 程序可以正常退出, 这样一些程序监视工具可以正常测到程序结束了
121 cmd.Start()
122 } else {
123 fmt.Println("Press [Enter] to exit...")
124 fmt.Scanln()
129 var cfgfile string
130 flag.StringVar(&cfgfile, "Config File", "./config.json", "Config file, json format")
131 flag.Parse()
133 var execFolder = "./"
134 if e, err := os.Executable(); err != nil {
135 log.Panicln(err)
136 } else {
137 execFolder = filepath.Dir(e)
139 // execFolder = "./"
141 gcfg := initConfig(cfgfile, execFolder)
142 disablePause = gcfg.DisablePause
144 var cfg *ScanConfig
145 scanMode := gcfg.ScanMode
146 switch scanMode {
147 case "quic":
148 cfg = &gcfg.Quic
149 testIPFunc = testQuic
150 case "tls":
151 cfg = &gcfg.Tls
152 testIPFunc = testTls
153 case "sni":
154 cfg = &gcfg.Sni
155 testIPFunc = testSni
156 case "ping":
157 cfg = &gcfg.Ping
158 testIPFunc = testPing
159 case "socks5":
160 // testIPFunc = testSocks5
161 default:
164 iprangeFile := cfg.InputFile
165 if _, err := os.Stat(iprangeFile); os.IsNotExist(err) {
166 log.Panicln(err)
169 srs := &ScanRecords{}
171 log.Printf("Start loading IP Range file: %s\n", iprangeFile)
172 ipqueue, err := parseIPRangeFile(iprangeFile)
173 if err != nil {
174 log.Panicln(err)
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 {
188 a[i] = r.IP
190 b := new(bytes.Buffer)
191 if cfg.OutputSeparator == "gop" {
192 out := strings.Join(a, `", "`)
193 b.WriteString(`"` + out + `",`)
194 } else {
195 out := strings.Join(a, cfg.OutputSeparator)
196 b.WriteString(out)
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)
201 } else {
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)
209 } else {
210 log.Printf("All results writed to %s\n", bakfilename)