prober.go
package main import ( "cnprober/log" "flag" "fmt" "io" "strings" "os" "time" "github.com/miekg/dns" "github.com/remeh/sizedwaitgroup" "github.com/spf13/viper" ) var logger = log.NewLogger() var timeout time.Duration = 5000 * time.Millisecond type Result struct { Servername string Serveraddr string Rtt time.Duration // 毫秒 DomainType string IPType string } func Lookup(fqdn, serverAddr string) (Result, error) { var m dns.Msg var result Result client := dns.Client{} client.Timeout = timeout m.SetQuestion(dns.Fqdn(fqdn), dns.TypeNS) _, rtt, err := client.Exchange(&m, serverAddr+":53") if err != nil { result.Rtt = timeout logger.Log("level", "error", "serverAddr", serverAddr, "resolveTime", result.Rtt) return result, err } logger.Log("level", "info", "serverAddr", serverAddr, "resolveTime", rtt) if rtt.Microseconds() < 1000 { rtt = 1 * time.Millisecond } result.Rtt = rtt return result, nil } func worker(fqdn string, serverName, serverAddr string, resultChannel chan Result, swg *sizedwaitgroup.SizedWaitGroup, flag string) { result, _ := Lookup(fqdn, serverAddr) domain_ip_type := strings.Split(flag, ".") domainType := domain_ip_type[0] ipType := domain_ip_type[1] result.DomainType = domainType result.IPType = ipType result.Serveraddr = serverAddr result.Servername = serverName resultChannel <- result } func openFile(filename string) (*os.File, error) { return os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY|os.O_TRUNC, 0666) } func writeFile(line string, f *os.File) { line = line + "\n" _, err := io.WriteString(f, line) if err != nil { logger.Log("level", "error", "msg", err) } } func run(flDomain *string, flWorkerCount *int, flResultProm *string, config *viper.Viper) { swg := sizedwaitgroup.New(*flWorkerCount) resultsChannel := make(chan Result) var results []Result go func() { for r := range resultsChannel { results = append(results, r) swg.Done() } }() for serverName, ip := range config.GetStringMap("cn.ipv4") { swg.Add() go worker(*flDomain, serverName, ip.(string), resultsChannel, &swg, "cn.ipv4") } for serverName, ip := range config.GetStringMap("cn.ipv6") { swg.Add() serverAddr := fmt.Sprintf("[%s]", ip.(string)) go worker(*flDomain, serverName, serverAddr, resultsChannel, &swg, "cn.ipv6") } for serverName, ip := range config.GetStringMap("root.ipv4") { swg.Add() go worker(*flDomain, serverName, ip.(string), resultsChannel, &swg, "root.ipv4") } for serverName, ip := range config.GetStringMap("root.ipv6") { swg.Add() serverAddr := fmt.Sprintf("[%s]", ip.(string)) go worker(*flDomain, serverName, serverAddr, resultsChannel, &swg, "root.ipv6") } swg.Wait() defer close(resultsChannel) f, err := openFile(*flResultProm) if err != nil { logger.Log("level", "error", "msg", err) } line1 := `# HELP authority_response_time # TYPE authority_response_time Gauge` writeFile(line1, f) for _, r := range results { // if r.Rtt.Milliseconds() < 5000 { // 如果取消注释,则在prom文件中不记录超时数据 line := fmt.Sprintf(`authority_response_time{server="%s", server_addr="%s", domain_type="%s", ip_type="%s"} %d`, r.Servername, r.Serveraddr, r.DomainType, r.IPType, r.Rtt.Milliseconds()) writeFile(line, f) // } } defer f.Close() } func main() { var ( flDomain = flag.String("domain", "", "The domain to perform fuzzing against.") flWorkerCount = flag.Int("c", 100, "The amount of worker to use") flResultProm = flag.String("prom", "response.prom", "The response result to save") flInterval = flag.Int("interval", 60, "The interval of worker to run") flConfig = flag.String("config", "config.toml", "The config file") ) flag.Parse() if *flDomain == "" { fmt.Println("domain are rquired, for example: cn") logger.Log("level", "error", "msg", "domain and wordlist are rquired") os.Exit(1) } if *flConfig == "" { fmt.Println("Cannot read config file " + *flConfig) logger.Log("level", "error", "msg", "Cannot read file "+*flConfig) os.Exit(2) } config := GetConfig(*flConfig) ticker := time.NewTicker(time.Duration(*flInterval) * time.Second) defer ticker.Stop() for range ticker.C { run(flDomain, flWorkerCount, flResultProm, config) } }
config.go
package main import ( "fmt" "github.com/spf13/viper" ) func GetConfig(configFile string) *viper.Viper { v := viper.New() v.SetConfigName(configFile) v.SetConfigType("toml") v.AddConfigPath(".") err := v.ReadInConfig() // 搜索并读取配置文件 if err != nil { // 处理错误 panic(fmt.Errorf("Fatal error config file: %s \n", err)) } return v }
logger.go
package log import ( "os" "time" "github.com/go-kit/log" ) var ( // This timestamp format differs from RFC3339Nano by using .000 instead // of .999999999 which changes the timestamp from 9 variable to 3 fixed // decimals (.130 instead of .130987456). timestampFormat = log.TimestampFormat( func() time.Time { return time.Now() }, "2006-01-02 15:04:05", ) ) // New returns a new leveled oklog logger. Each logged line will be annotated // with a timestamp. The output always goes to stderr. func NewLogger() log.Logger { var l log.Logger l = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) l = log.With(l, "ts", timestampFormat, "caller", log.DefaultCaller) return l }
config.toml
[cn] [cn.ipv4] "a.dns.cn." = "203.119.25.1" "b.dns.cn." = "203.119.26.1" "c.dns.cn." = "203.119.27.1" "d.dns.cn." = "203.119.28.1" "e.dns.cn." = "203.119.29.1" "f.dns.cn." = "195.219.8.90" "g.dns.cn." = "66.198.183.65" "ns.cernet.net." = "202.112.0.44" [cn.ipv6] "a.dns.cn." = "2001:dc7:0:0:0:0:0:1" "d.dns.cn." = "2001:dc7:1000:0:0:0:0:1" [root] [root.ipv4] "a.root-servers.net." = "198.41.0.4" "b.root-servers.net." = "199.9.14.201" "c.root-servers.net." = "192.33.4.12" "d.root-servers.net." = "199.7.91.13" "e.root-servers.net." = "192.203.230.10" "f.root-servers.net." = "192.5.5.241" "g.root-servers.net." = "192.112.36.4" "h.root-servers.net." = "198.97.190.53" "i.root-servers.net." = "192.36.148.17" "j.root-servers.net." = "192.58.128.30" "k.root-servers.net." = "193.0.14.129" "l.root-servers.net." = "199.7.83.42" "m.root-servers.net." = "202.12.27.33" [root.ipv6] "a.root-servers.net." = "2001:503:ba3e::2:30" "b.root-servers.net." = "2001:500:200::b" "c.root-servers.net." = "2001:500:2::c" "d.root-servers.net." = "2001:500:2d::d" "e.root-servers.net." = "2001:500:a8::e" "f.root-servers.net." = "2001:500:2f::f" "g.root-servers.net." = "2001:500:12::d0d" "h.root-servers.net." = "2001:500:1::53" "i.root-servers.net." = "2001:7fe::53" "j.root-servers.net." = "2001:503:c27::2:30" "k.root-servers.net." = "2001:7fd::1" "l.root-servers.net." = "2001:500:9f::42" "m.root-servers.net." = "2001:dc3::35"