diff --git a/checker/checker.go b/checker/checker.go index d10787e..ddddaad 100644 --- a/checker/checker.go +++ b/checker/checker.go @@ -1,9 +1,11 @@ package main import ( + "errors" "fmt" "io/ioutil" "log" + "net" "net/http" "time" @@ -35,21 +37,73 @@ func check_ping(ip string, cb func(pkt *ping.Packet)) (err error) { // PORT 53 -func check_dns(domain, ip string) (err error) { +func get_GLUE(domain string) (aaaa net.IP, err error) { + client := dns.Client{Net: "tcp", Timeout: time.Second * 5} + + m := new(dns.Msg) + m.SetQuestion(domain, dns.TypeNS) + m.RecursionDesired = false + m.SetEdns0(4096, true) + + var r *dns.Msg + r, _, err = client.Exchange(m, "[2a01:e0a:25a:9160::2]:53") + if err != nil { + return + } + + if r == nil { + return nil, errors.New("response is nil") + } + if r.Rcode != dns.RcodeSuccess { + return nil, errors.New("failed to get a valid answer") + } + + for _, extra := range r.Extra { + if t, ok := extra.(*dns.AAAA); ok { + aaaa = t.AAAA + } + } + + return +} + +func check_dns(domain, ip string) (aaaa net.IP, err error) { client := dns.Client{Timeout: time.Second * 5} m := new(dns.Msg) - m.SetQuestion(domain, dns.TypeSOA) + m.SetQuestion(domain, dns.TypeAAAA) + + var r *dns.Msg + r, _, err = client.Exchange(m, fmt.Sprintf("[%s]:53", ip)) + if err != nil { + return + } + + if r == nil { + err = errors.New("response is nil") + } + if r.Rcode != dns.RcodeSuccess { + err = errors.New("failed to get a valid answer") + } + + if len(r.Answer) > 0 { + aaaa = r.Answer[0].(*dns.AAAA).AAAA + } - _, _, err = client.Exchange(m, fmt.Sprintf("[%s]:53", ip)) return } // PORT 80 func check_http(ip string) (err error) { + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + var resp *http.Response - resp, err = http.Get(fmt.Sprintf("http://[%s]/", ip)) + resp, err = client.Get(fmt.Sprintf("http://[%s]/", ip)) if err != nil { return } @@ -118,32 +172,20 @@ func studentsChecker() { return } - // Check HTTP - if err := check_http(stdIP); err == nil { - if verbose { - log.Printf("%s just unlocked HTTP challenge\n", std.Login) - } - if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+0, ""); err != nil { - if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+0, ""); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } - } - } + dnsIP := stdIP + // Is GLUE defined? + if glueIP, err := get_GLUE(std.MyDelegatedDomain()); glueIP != nil { + dnsIP = glueIP.String() - // Check HTTPs - if err := check_https(std.MyAssociatedDomain(), stdIP); err == nil { if verbose { - log.Printf("%s just unlocked HTTPS challenge\n", std.Login) - } - if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+1, ""); err != nil { - if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+1, ""); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } + log.Printf("%s has defined GLUE: %s\n", std.Login, dnsIP) } + } else if err != nil { + log.Printf("%s and GLUE: %s\n", std.Login, err) } // Check DNS - if err := check_dns(std.MyDelegatedDomain(), stdIP); err == nil { + if addr, err := check_dns(std.MyDelegatedDomain(), dnsIP); err == nil { if verbose { log.Printf("%s just unlocked DNS challenge\n", std.Login) } @@ -152,6 +194,66 @@ func studentsChecker() { log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) } } + + // Check HTTP with DNS + if addr == nil { + log.Printf("%s and HTTP (with DNS ip=%s): skipped due to empty response\n", std.Login, addr.String()) + } else if err := check_http(addr.String()); err == nil { + if verbose { + log.Printf("%s just unlocked HTTP challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+0, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+0, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTP (with DNS ip=%s): %s\n", std.Login, addr.String(), err) + } + + // Check HTTPs with DNS + if addr == nil { + log.Printf("%s and HTTPS (with DNS ip=%s): skipped due to empty response\n", std.Login, addr.String()) + } else if err := check_https(std.MyDelegatedDomain(), addr.String()); err == nil { + if verbose { + log.Printf("%s just unlocked HTTPS challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+1, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+1, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTPS (with DNS ip=%s): %s\n", std.Login, addr.String(), err) + } + } else { + // Check HTTP without DNS + if err := check_http(stdIP); err == nil { + if verbose { + log.Printf("%s just unlocked HTTP challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+0, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+0, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTP (without DNS): %s\n", std.Login, err) + } + + // Check HTTPs without DNS + if err := check_https(std.MyAssociatedDomain(), stdIP); err == nil { + if verbose { + log.Printf("%s just unlocked HTTPS challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+1, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+1, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTPS (without DNS): %s\n", std.Login, err) + } } return