package main import ( "database/sql" "encoding/json" "encoding/xml" "fmt" "html/template" "log" "net" "net/http" "os" "io" "strings" "bytes" "errors" _ "modernc.org/sqlite" ) type Config struct { Port uint SiteName string } type page struct { Title string } type xmlDomain struct { authority string registryType string entityClass string entityName string } var C = Config{} var db *sql.DB func main() { var err error domain := "snuff.fi" av, err := checkDomainAvailability(domain) if err != nil { log.Fatal(err) os.Exit(1) } fmt.Printf("Domain '%s' available: %t\n", domain, av) return // Load config fmt.Println("Loading config.json") cfgfile, err := os.Open("config.json") if err != nil { log.Fatal("Error reading config.json!") os.Exit(1) } defer cfgfile.Close() decoder := json.NewDecoder(cfgfile) //Config := Config{} err = decoder.Decode(&C) if err != nil { log.Fatal("Can't decode config.json!") os.Exit(1) } db, err = sql.Open("sqlite", "database.db") if err != nil { log.Fatal(err) os.Exit(1) } fmt.Printf("Starting listener on :%v", C.Port) http.Handle("/static/", http.FileServer(http.Dir("./"))) http.HandleFunc("/", httpRootHandler) err = http.ListenAndServe(fmt.Sprintf(":%v", C.Port), nil) if err != nil { log.Fatal(err) } db.Close() } func httpRootHandler(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("index.html") // var err := do_get_stuff() // if err != nil { // log.Fatal(err) // http.Error(w, http.StatusText(500), 500) // return // } var p page p.Title = C.SiteName; t.Execute(w, p) } func checkDomainAvailability(domain string) (bool, error) { dasHost := "das.domain.fi"; dasPort := 715 dasAddr := fmt.Sprintf("%s:%d", dasHost, dasPort) request := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> <iris1:request xmlns:iris1="urn:ietf:params:xml:ns:iris1"> <iris1:searchSet> <iris1:lookupEntity registryType="dchk1" entityClass="domain-name" entityName="%s"/> </iris1:searchSet> </iris1:request>`, domain) conn, err := net.Dial("udp", dasAddr) if err != nil { log.Fatal(err) return false, err } defer conn.Close() fmt.Fprintf(conn, request) response := make([]byte, 1024) _, err = conn.Read(response) if err != nil { log.Fatal(err) } response = bytes.Trim(response, "\x00") // Response can be: // - active: already in use // - available: go ahead and grab it while you can // - invalid: malformed request: maybe check domain has .fi in the end isAvailable, err := xmlCheckTag(string(response), "available") if err != nil { log.Fatal(err) return false, err } else if isAvailable { // Domain is available return true, nil } isActive, err := xmlCheckTag(string(response), "active") if err != nil { log.Fatal(err) return false, err } else if isActive { // Domain is already registered taken return false, nil } isInvalid, err := xmlCheckTag(string(response), "invalid") if err != nil { log.Fatal(err) return false, err } else if isInvalid { // We got bonked for our request return false, errors.New("Request or domain invalid") } // Execution should not lead here but hey might as well error it out return false, errors.New("Error: Status field not found") } func xmlCheckTag(src, tag string) (bool, error) { // Thanks icza for your stackoverflow // https://stackoverflow.com/a/51649834 decoder := xml.NewDecoder(strings.NewReader(src)) for { t, err := decoder.Token() if err != nil { if err == io.EOF { return false, nil } return false, err } if se, ok := t.(xml.StartElement); ok { if se.Name.Local == tag { return true, nil } } } }