diff --git a/dns.go b/dns.go
index 693c0fa..720f903 100644
--- a/dns.go
+++ b/dns.go
@@ -141,21 +141,24 @@ func handleDNSStd(w dns.ResponseWriter, r *dns.Msg) {
m.Answer = getv4stdRR()
latest.mtx.RUnlock()
qtype = "A"
+ // start a goroutine to update the global counters then get back to answering this request
+ go updateDNSCounts(dnsV4Std)
case dns.TypeAAAA:
latest.mtx.RLock()
m.Answer = getv6stdRR()
latest.mtx.RUnlock()
qtype = "AAAA"
+ go updateDNSCounts(dnsV6Std)
default:
// return no answer to all other queries
}
+
+ w.WriteMsg(m)
+
if config.verbose {
log.Printf("status - DNS response Type: standard To IP: %s Query Type: %s\n", w.RemoteAddr().String(), qtype)
}
-
- // FIXME - add stats and query counts
- w.WriteMsg(m)
}
// handleDNSNon processes a DNS request from remote client and returns
@@ -177,21 +180,24 @@ func handleDNSNon(w dns.ResponseWriter, r *dns.Msg) {
m.Answer = getv4nonRR()
latest.mtx.RUnlock()
qtype = "A"
+ // start a goroutine to update the global counters then get back to answering this request
+ go updateDNSCounts(dnsV4Non)
case dns.TypeAAAA:
latest.mtx.RLock()
m.Answer = getv6nonRR()
latest.mtx.RUnlock()
qtype = "AAAA"
+ go updateDNSCounts(dnsV6Non)
default:
// return no answer to all other queries
}
+
+ w.WriteMsg(m)
+
if config.verbose {
log.Printf("status - DNS response Type: non-standard To IP: %s Query Type: %s\n", w.RemoteAddr().String(), qtype)
}
-
- // FIXME - add stats and query counts
- w.WriteMsg(m)
}
// serve starts the requested DNS server listening on the requested port
diff --git a/http.go b/http.go
index 109340b..d762963 100644
--- a/http.go
+++ b/http.go
@@ -390,6 +390,43 @@ func generateWebStatus(status uint32) (ws []webstatus) {
// genHeader will output the standard header
func writeHeader(w http.ResponseWriter, r *http.Request) {
+
+ var hc struct {
+ RG uint32
+ RGS uint32
+ CG uint32
+ CGS uint32
+ WG uint32
+ WGS uint32
+ NG uint32
+ NGS uint32
+ Total uint32
+ V4Std uint32
+ V4Non uint32
+ V6Std uint32
+ V6Non uint32
+ DNSTotal uint32
+ }
+
+ // fill the structs so they can be displayed via the template
+ counts.mtx.RLock()
+ hc.RG = counts.TwStatus[statusRG]
+ hc.RGS = counts.TwStarts[statusRG]
+ hc.CG = counts.TwStatus[statusCG]
+ hc.CGS = counts.TwStarts[statusCG]
+ hc.WG = counts.TwStatus[statusWG]
+ hc.WGS = counts.TwStarts[statusWG]
+ hc.NG = counts.TwStatus[statusNG]
+ hc.NGS = counts.TwStarts[statusNG]
+ hc.Total = hc.RG + hc.CG + hc.WG + hc.NG
+
+ hc.V4Std = counts.DNSCounts[dnsV4Std]
+ hc.V4Non = counts.DNSCounts[dnsV4Non]
+ hc.V6Std = counts.DNSCounts[dnsV6Std]
+ hc.V6Non = counts.DNSCounts[dnsV6Non]
+ hc.DNSTotal = hc.V4Std + hc.V4Non + hc.V6Std + hc.V6Non
+ counts.mtx.RUnlock()
+
// we are using basic and simple html here. No fancy graphics or css
h := `
@@ -401,22 +438,28 @@ func writeHeader(w http.ResponseWriter, r *http.Request) {
statusNG
DNS
- Current Stats (count/started)
+
+ Twistee Stats (count/started)
- RG: {{.RG}}/{{.RGS}} | CG: {{.CG}}/{{.CGS}} | WG: {{.WG}}/{{.WGS}} | NG: {{.NG}}/{{.NGS}} | Total: {{.Total}} |
+ RG: {{.RG}}/{{.RGS}} | CG: {{.CG}}/{{.CGS}} | WG: {{.WG}}/{{.WGS}} | NG: {{.NG}}/{{.NGS}} | Total: {{.Total}} |
+ |
+ DNS Requests
+
+ V4 Std: {{.V4Std}} | V4 Non: {{.V4Non}} | V6 Std: {{.V6Std}} | V6 Non: {{.V6Non}} | Total: {{.DNSTotal}} |
+
+ |
`
+
t := template.New("Header template")
t, err := t.Parse(h)
if err != nil {
log.Printf("error parsing template %v\n", err)
}
- counts.mtx.RLock()
- err = t.Execute(w, counts)
- counts.mtx.RUnlock()
+ err = t.Execute(w, hc)
if err != nil {
log.Printf("error executing template %v\n", err)
}
diff --git a/main.go b/main.go
index 4f4fdef..5df152d 100644
--- a/main.go
+++ b/main.go
@@ -9,12 +9,22 @@ import (
"log"
"os"
"os/signal"
+ "sync"
"syscall"
"time"
"github.com/miekg/dns"
)
+// twCounts holds various statistics about the running system
+type twCounts struct {
+ TwStatus []uint32
+ TwStarts []uint32
+ DNSCounts []uint32
+ mtx sync.RWMutex
+}
+
+// configData holds information on the application
type configData struct {
host string
port string
@@ -34,6 +44,11 @@ func main() {
// FIXME - update with git hash during build
config.version = "0.5.0"
+ // initialize the stats counters
+ counts.TwStatus = make([]uint32, maxStatusTypes)
+ counts.TwStarts = make([]uint32, maxStatusTypes)
+ counts.DNSCounts = make([]uint32, maxDNSTypes)
+
flag.StringVar(&config.host, "h", "", "DNS host to serve")
flag.StringVar(&config.port, "p", "8053", "Port to listen on")
flag.BoolVar(&config.verbose, "v", false, "Display verbose output")
@@ -117,6 +132,23 @@ func main() {
fmt.Printf("\nProgram exiting. Bye\n")
}
+// updateTwCounts runs in a goroutine and updates the global stats with the lates
+// counts from a startCrawlers run
+func updateTwCounts(status, total, started uint32) {
+ // update the stats counters
+ counts.mtx.Lock()
+ counts.TwStatus[status] = total
+ counts.TwStarts[status] = started
+ counts.mtx.Unlock()
+}
+
+// updateDNSCounts runs in a goroutine and updates the global stats for the number of DNS requests
+func updateDNSCounts(dnsType uint32) {
+ counts.mtx.Lock()
+ counts.DNSCounts[dnsType]++
+ counts.mtx.Unlock()
+}
+
/*
*/
diff --git a/seeder.go b/seeder.go
index 7ab3d2f..5a3dca5 100644
--- a/seeder.go
+++ b/seeder.go
@@ -27,32 +27,21 @@ const (
maxTo = 250 // max seconds (4min 10 sec) for all comms to twistee to complete before we timeout
- dnsV4Std = 1
- dnsV4Non = 2
- dnsV6Std = 3
- dnsV6Non = 4
+ dnsInvalid = 0
+ dnsV4Std = 1
+ dnsV4Non = 2
+ dnsV6Std = 3
+ dnsV6Non = 4
+ maxDNSTypes = 5
// twistee status
- statusRG = 1 // reported good status. A remote twistee has reported this ip but we have not connected
- statusCG = 2 // confirmed good. We have connected to the twistee and received addresses
- statusWG = 3 // was good. Twistee was confirmed good but now having problems
- statusNG = 4 // no good. Will be removed from theList after 24 hours to redure bouncing ip addresses
-
+ statusRG = 1 // reported good status. A remote twistee has reported this ip but we have not connected
+ statusCG = 2 // confirmed good. We have connected to the twistee and received addresses
+ statusWG = 3 // was good. Twistee was confirmed good but now having problems
+ statusNG = 4 // no good. Will be removed from theList after 24 hours to redure bouncing ip addresses
+ maxStatusTypes = 5
)
-type twCounts struct {
- RG uint32
- RGS uint32
- CG uint32
- CGS uint32
- WG uint32
- WGS uint32
- NG uint32
- NGS uint32
- Total int
- mtx sync.RWMutex
-}
-
type dnsseeder struct {
uptime time.Time
theList map[string]*twistee
@@ -144,30 +133,16 @@ func (s *dnsseeder) startCrawlers() {
continue
}
- // all looks go so start a go routine to crawl the remote twistee
+ // all looks good so start a go routine to crawl the remote twistee
go crawlTwistee(tw)
c.started++
}
log.Printf("stats - started crawler: %s total: %v started: %v\n", c.desc, c.totalCount, c.started)
- counts.mtx.Lock()
- switch c.status {
- case statusRG:
- counts.RG = c.totalCount
- counts.RGS = c.started
- case statusCG:
- counts.CG = c.totalCount
- counts.CGS = c.started
- case statusWG:
- counts.WG = c.totalCount
- counts.WGS = c.started
- case statusNG:
- counts.NG = c.totalCount
- counts.NGS = c.started
- }
- counts.Total = tcount
- counts.mtx.Unlock()
+ // update the global stats in another goroutine to free the main goroutine
+ // for other work
+ go updateTwCounts(c.status, c.totalCount, c.started)
}
log.Printf("stats - crawlers started. total twistees: %d\n", tcount)