package main
import (
"context"
"fmt"
"io"
"net"
"net/url"
"strings"
"github.com/fastly/compute-sdk-go/fsthttp"
"github.com/valyala/fastjson"
)
type Outcome int
const (
MissingQueryString Outcome = iota
InvalidQueryString
GoogleDnsFailed
IsGoogleBot
NotGoogleBot
NoPtrAnser
)
const Backend = "origin_0"
func (o Outcome) Into(w fsthttp.ResponseWriter, ptr string) fsthttp.ResponseWriter {
var result string
var reason string
var status int
switch o {
case MissingQueryString:
result = "error"
reason = "Missing query string ?ip=a.b.c.d"
status = fsthttp.StatusBadRequest
case InvalidQueryString:
result = "error"
reason = "Invalid query string ?ip=a.b.c.d"
status = fsthttp.StatusBadRequest
case GoogleDnsFailed:
result = "error"
reason = "Google DNS failed\n" + ptr
status = fsthttp.StatusBadGateway
case IsGoogleBot:
result = "yes"
reason = "Reverse lookup is " + ptr
status = fsthttp.StatusOK
case NotGoogleBot:
result = "no"
reason = "Reverse lookup is " + ptr + ", not an *.google.com or *.googlebot.com domain."
status = fsthttp.StatusOK
case NoPtrAnser:
result = "no"
reason = "No PTR Answer for this reverse lookup."
status = fsthttp.StatusOK
}
w.Header().Set("x-googlebot-verified", result)
w.Header().Set("x-googlebot-verified-reason", reason)
w.WriteHeader(status)
fmt.Fprintf(w, `{"result": "%s", "reason": "%s"}\n`, result, reason)
return w
}
func main() {
fsthttp.ServeFunc(func(ctx context.Context, w fsthttp.ResponseWriter, r *fsthttp.Request) {
if r.URL.Path == "/verify" && r.Method == "GET" {
w = handle_lookup_request(ctx, w, *r)
return
}
w.WriteHeader(fsthttp.StatusNotFound)
fmt.Fprintf(w, "The page you requested could not be found\n")
})
}
func handle_lookup_request(ctx context.Context, w fsthttp.ResponseWriter, req fsthttp.Request) fsthttp.ResponseWriter {
var qs_params = req.URL.RawQuery
if qs_params == "" {
return MissingQueryString.Into(w, "")
}
qs_map, err := url.ParseQuery(qs_params)
if err != nil {
fmt.Print(err)
return MissingQueryString.Into(w, "")
}
ipaddrStr := strings.Join(qs_map["ip"], "")
if ipaddrStr == "" {
return InvalidQueryString.Into(w, "")
}
ipaddr := net.ParseIP(ipaddrStr)
if ipaddr == nil {
return InvalidQueryString.Into(w, "")
}
ipaddr_slice := strings.Split(ipaddrStr, ".")
req.URL, err = url.Parse("https://dns.google.com/resolve?name=" + ipaddr_slice[3] + "." + ipaddr_slice[2] + "." + ipaddr_slice[1] + "." + ipaddr_slice[0] + ".in-addr.arpa&type=PTR")
if err != nil {
fmt.Print("URL: ", err)
}
req.Header.Del("accept-encoding")
resp, err := req.Send(ctx, Backend)
if err != nil {
fmt.Print(err)
return GoogleDnsFailed.Into(w, "Send error: " + err.Error())
}
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Print(err)
return GoogleDnsFailed.Into(w, "Read error: " + err.Error())
}
fmt.Println("Body String: ", string(body))
var p fastjson.Parser
body_json, err := p.ParseBytes(body)
if err != nil {
fmt.Print(err)
return GoogleDnsFailed.Into(w, "Parse error:" + err.Error())
}
ptr_record := body_json.Get("Answer", "0", "data").GetStringBytes()
if ptr_record == nil {
return NoPtrAnser.Into(w, "")
}
if strings.HasSuffix(string(ptr_record), ".google.com.") || strings.HasSuffix(string(ptr_record), ".googlebot.com.") {
return IsGoogleBot.Into(w, string(ptr_record))
}
return NotGoogleBot.Into(w, string(ptr_record))
}