diff options
Diffstat (limited to 'internal/qna')
-rw-r--r-- | internal/qna/qna.go | 109 |
1 files changed, 108 insertions, 1 deletions
diff --git a/internal/qna/qna.go b/internal/qna/qna.go index bd2078d..809df15 100644 --- a/internal/qna/qna.go +++ b/internal/qna/qna.go @@ -1,12 +1,119 @@ package qna +import ( + "fmt" + "net" + "net/url" +) + type Question struct { Domain string // domain name to visit via HTTPS } type Answer struct { Domain string // domain name of the visited HTTPS site - OK bool // true if HTTP GET request succeeded HTTP string // value set in the Onion-Location HTTP header (if any) HTML string // value set in the Onion-Location HTML attribute (if any) + + ReqErr error // nil if HTTP GET request could be constructed + DoErr error // nil if HTTP GET request could be executed +} + +func (a Answer) String() string { + if a.ReqErr != nil { + return fmt.Sprintf("%s: %v", a.ReqErr) + } + if a.DoErr != nil { + return fmt.Sprintf("%s: %v", a.DoErr) + } + if a.HTTP == "" && a.HTML == "" { + return fmt.Sprintf("%s: connected but found no Onion-Location") + } + return fmt.Sprintf("%s header=%s attribute=%s", a.Domain, a.HTTP, a.HTML) +} + +type Progress struct { + NumReqErr int // error before sending requests + NumDoErr int // error while sending request + NumOK int // got response + NumOnion int // found onion in response + + // More details about DNS errors while sending request + NumDNSNotFound int + NumDNSTimeout int + NumDNSOther int +} + +func (p Progress) String() string { + str := fmt.Sprintf(" Processed: %d\n", p.NumAnswer()) + str += fmt.Sprintf(" Success: %d (Onion-Location:%d)\n", p.NumOK, p.NumOnion) + str += fmt.Sprintf(" Failure: %d (Req:%d Do:%d)\n", p.NumError(), p.NumReqErr, p.NumDoErr) + str += fmt.Sprintf(" DNS: %d (NotFound:%d Timeout:%d Other:%d)", + p.NumDNSErr(), p.NumDNSNotFound, p.NumDNSTimeout, p.NumDNSOther) + return str +} + +func (p *Progress) NumAnswer() int { + return p.NumReqErr + p.NumDoErr + p.NumOK +} + +func (p *Progress) NumError() int { + return p.NumReqErr + p.NumDoErr +} + +func (p *Progress) NumDNSErr() int { + return p.NumDNSNotFound + p.NumDNSTimeout + p.NumDNSOther +} + +func (p *Progress) AddAnswer(a Answer) { + if a.ReqErr != nil { + p.NumReqErr += 1 + return + } + if a.DoErr != nil { + p.NumDoErr += 1 + err := dnsError(a.DoErr) + if err == nil { + return + } + + if err.IsTimeout { + p.NumDNSTimeout += 1 + } else if err.IsNotFound { + p.NumDNSNotFound += 1 + } else { + p.NumDNSOther += 1 + } + return + } + + p.NumOK += 1 + if a.HTTP != "" || a.HTML != "" { + p.NumOnion += 1 + } +} + +func dnsError(err error) *net.DNSError { + if err == nil { + return nil + } + + urlErr, ok := err.(*url.Error) + if !ok { + return nil + } + + err = urlErr.Err + opErr, ok := err.(*net.OpError) + if !ok { + return nil + } + + err = opErr.Err + dnsErr, ok := err.(*net.DNSError) + if !ok { + return nil + } + + return dnsErr } |