2025-05-14 22:00:38 -04:00
|
|
|
package whois
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
2026-06-04 12:45:39 -04:00
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
"hub.krkn.tech/KrakenTech/crowsnest/internal/debug"
|
|
|
|
|
"hub.krkn.tech/KrakenTech/crowsnest/internal/dehashed"
|
|
|
|
|
"hub.krkn.tech/KrakenTech/crowsnest/internal/sqlite"
|
2025-05-14 22:00:38 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type DehashedWHOISSearchRequest struct {
|
|
|
|
|
Include []string `json:"include,omitempty"`
|
|
|
|
|
Exclude []string `json:"exclude,omitempty"`
|
|
|
|
|
IPAddress string `json:"ip_address,omitempty"`
|
|
|
|
|
ReverseType string `json:"reverse_type,omitempty"`
|
|
|
|
|
Domain string `json:"domain,omitempty"`
|
|
|
|
|
MXAddress string `json:"mx_address,omitempty"`
|
|
|
|
|
NSAddress string `json:"ns_address,omitempty"`
|
|
|
|
|
SearchType string `json:"search_type,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
type DehashedWhoIs struct {
|
|
|
|
|
balance int
|
|
|
|
|
debug bool
|
|
|
|
|
apiKey string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewWhoIs(apiKey string, debug bool) *DehashedWhoIs {
|
|
|
|
|
return &DehashedWhoIs{apiKey: apiKey, debug: debug, balance: -1}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *DehashedWhoIs) WhoisSearch(domain string) (sqlite.WhoisRecord, error) {
|
2025-05-14 22:00:38 -04:00
|
|
|
var whois sqlite.WhoIsLookupResult
|
2025-05-16 15:33:29 -04:00
|
|
|
var whoisRecord sqlite.WhoisRecord
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois search")
|
|
|
|
|
zap.L().Info("whois_search_debug",
|
|
|
|
|
zap.String("message", "performing whois search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
whoisSearchRequest := DehashedWHOISSearchRequest{
|
|
|
|
|
Domain: domain,
|
|
|
|
|
SearchType: "whois",
|
|
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("whois_search_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
|
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisRecord, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("setting headers")
|
|
|
|
|
zap.L().Info("whois_search_debug",
|
|
|
|
|
zap.String("message", "setting headers"),
|
|
|
|
|
)
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("headers set")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
debug.PrintInfo("performing request")
|
|
|
|
|
zap.L().Info("whois_search_debug",
|
|
|
|
|
zap.String("message", "performing request"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_search",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisRecord, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_search",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisRecord, errors.New("response was nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
zap.L().Error("whois_search",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return whoisRecord, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
|
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("whois_search",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisRecord, &dhErr
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(b, &whois)
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to unmarshal response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-14 22:00:38 -04:00
|
|
|
zap.L().Error("whois_search",
|
|
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
fmt.Println("Error unmarshalling response body:", err)
|
|
|
|
|
fmt.Println("Response body:", string(b))
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisRecord, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whois.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whois.Data))
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
w.balance = whois.RemainingCredits
|
2025-05-14 22:00:38 -04:00
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
return whois.Data.WhoisRecord, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
func (w *DehashedWhoIs) WhoisHistory(domain string) ([]sqlite.HistoryRecord, error) {
|
2025-05-14 22:00:38 -04:00
|
|
|
var whois sqlite.WhoIsHistory
|
2025-05-16 15:33:29 -04:00
|
|
|
var historyRecords []sqlite.HistoryRecord
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois history search")
|
|
|
|
|
zap.L().Info("whois_history_debug",
|
|
|
|
|
zap.String("message", "performing whois history search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
whoisSearchRequest := DehashedWHOISSearchRequest{
|
|
|
|
|
Domain: domain,
|
|
|
|
|
SearchType: "whois-history",
|
|
|
|
|
}
|
|
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("whois_history_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to create request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_history",
|
|
|
|
|
zap.String("message", "failed to create request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return historyRecords, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing request")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
zap.L().Info("whois_history_debug",
|
|
|
|
|
zap.String("message", "performing request"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was not nil")
|
|
|
|
|
}
|
2025-05-14 22:00:38 -04:00
|
|
|
zap.L().Info("whois_history",
|
|
|
|
|
zap.String("message", "response was not nil"),
|
|
|
|
|
)
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-14 22:00:38 -04:00
|
|
|
zap.L().Error("whois_history",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return historyRecords, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-14 22:00:38 -04:00
|
|
|
zap.L().Error("whois_history",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return historyRecords, errors.New("response was nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to read response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_history",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return historyRecords, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
|
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("whois_history",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return historyRecords, &dhErr
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(b, &whois)
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to unmarshal response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-14 22:00:38 -04:00
|
|
|
zap.L().Error("whois_history",
|
|
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
fmt.Println("Error unmarshalling response body:", err)
|
|
|
|
|
fmt.Println("Response body:", string(b))
|
2025-05-16 15:33:29 -04:00
|
|
|
return historyRecords, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whois.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whois.Data))
|
|
|
|
|
}
|
|
|
|
|
w.balance = whois.RemainingCredits
|
|
|
|
|
|
|
|
|
|
return whois.Data.Records, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-17 12:58:37 -04:00
|
|
|
func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverseType string) (sqlite.ReverseWhoisData, error) {
|
|
|
|
|
var whois sqlite.ReverseWhoisData
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing reverse whois search")
|
|
|
|
|
zap.L().Info("reverse_whois_debug",
|
|
|
|
|
zap.String("message", "performing reverse whois search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
whoisSearchRequest := DehashedWHOISSearchRequest{
|
|
|
|
|
Include: include,
|
|
|
|
|
Exclude: exclude,
|
|
|
|
|
ReverseType: reverseType,
|
|
|
|
|
SearchType: "reverse-whois",
|
|
|
|
|
}
|
|
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("reverse_whois_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.L().Error("reverse_whois",
|
|
|
|
|
zap.String("message", "failed to create request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-17 12:58:37 -04:00
|
|
|
return whois, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing reverse whois search")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
zap.L().Info("reverse_whois_debug",
|
|
|
|
|
zap.String("message", "performing reverse whois search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("reverse_whois",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-17 12:58:37 -04:00
|
|
|
return whois, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("reverse_whois",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-17 12:58:37 -04:00
|
|
|
return whois, errors.New("response was nil")
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to read response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("reverse_whois",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-17 12:58:37 -04:00
|
|
|
return whois, err
|
2025-05-16 15:33:29 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-15 16:23:59 -04:00
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("reverse_whois",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
2025-05-17 12:58:37 -04:00
|
|
|
return whois, &dhErr
|
2025-05-15 16:23:59 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-17 12:58:37 -04:00
|
|
|
var whoisResponse sqlite.ReverseWhoisResponse
|
|
|
|
|
err = json.Unmarshal(b, &whoisResponse)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to unmarshal response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("reverse_whois",
|
|
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return whois, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whoisResponse.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whoisResponse.Data))
|
|
|
|
|
}
|
|
|
|
|
w.balance = whoisResponse.RemainingCredits
|
|
|
|
|
|
|
|
|
|
whois = whoisResponse.Data
|
|
|
|
|
|
|
|
|
|
return whois, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
func (w *DehashedWhoIs) WhoisIP(ipAddress string) ([]sqlite.LookupResult, error) {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois ip search")
|
|
|
|
|
zap.L().Info("whois_ip_debug",
|
|
|
|
|
zap.String("message", "performing whois ip search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type IPSearchRequest struct {
|
|
|
|
|
IPAddress string `json:"domain"`
|
|
|
|
|
SearchType string `json:"search_type"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
whoisSearchRequest := IPSearchRequest{
|
2025-05-14 22:00:38 -04:00
|
|
|
IPAddress: ipAddress,
|
|
|
|
|
SearchType: "reverse-ip",
|
|
|
|
|
}
|
|
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("whois_ip_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.L().Error("whois_ip",
|
|
|
|
|
zap.String("message", "failed to create request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-14 22:00:38 -04:00
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois ip search")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
zap.L().Info("whois_ip_debug",
|
|
|
|
|
zap.String("message", "performing whois ip search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_ip",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-14 22:00:38 -04:00
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_ip",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-14 22:00:38 -04:00
|
|
|
return nil, errors.New("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to read response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_ip",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-15 16:23:59 -04:00
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("whois_ip",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
|
|
|
|
return nil, &dhErr
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("read response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Response Body: %s\n", string(b)))
|
|
|
|
|
zap.L().Info("whois_ip_debug",
|
|
|
|
|
zap.String("message", "read response body"),
|
|
|
|
|
zap.String("body", string(b)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var whois sqlite.WhoIsIPLookup
|
|
|
|
|
err = json.Unmarshal(b, &whois)
|
2025-05-14 22:00:38 -04:00
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to unmarshal response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_ip",
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-14 22:00:38 -04:00
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whois.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whois.Data))
|
|
|
|
|
}
|
|
|
|
|
w.balance = whois.RemainingCredits
|
|
|
|
|
var lookups []sqlite.LookupResult
|
|
|
|
|
|
|
|
|
|
for _, v := range whois.Data.Result {
|
|
|
|
|
lookups = append(lookups, sqlite.LookupResult{
|
|
|
|
|
FirstSeen: v.FirstSeen,
|
|
|
|
|
LastVisit: v.LastVisit,
|
|
|
|
|
Name: v.Name,
|
|
|
|
|
SearchTerm: ipAddress,
|
|
|
|
|
Type: "Reverse IP",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-17 10:25:16 -04:00
|
|
|
sqlite.StoreWhoisLookup(lookups)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
return lookups, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
func (w *DehashedWhoIs) WhoisMX(mxHostname string) ([]sqlite.LookupResult, error) {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois mx search")
|
|
|
|
|
zap.L().Info("whois_mx_debug",
|
|
|
|
|
zap.String("message", "performing whois mx search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ReverseMX struct {
|
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
|
SearchType string `json:"search_type"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
whoisSearchRequest := ReverseMX{
|
|
|
|
|
Domain: mxHostname,
|
2025-05-14 22:00:38 -04:00
|
|
|
SearchType: "reverse-mx",
|
|
|
|
|
}
|
|
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("whois_mx_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to create request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_mx",
|
|
|
|
|
zap.String("message", "failed to create request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois mx search")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
zap.L().Info("whois_mx_debug",
|
|
|
|
|
zap.String("message", "performing whois mx search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_mx",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_mx",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, errors.New("response was nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to read response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_mx",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
|
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("whois_mx",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, &dhErr
|
2025-05-15 16:23:59 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("read response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var whois sqlite.WhoIsMXLookup
|
|
|
|
|
err = json.Unmarshal(b, &whois)
|
2025-05-14 22:00:38 -04:00
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to unmarshal response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_mx",
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whois.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whois.Data))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var mxLookups []sqlite.LookupResult
|
|
|
|
|
|
|
|
|
|
for _, v := range whois.Data.Result {
|
|
|
|
|
mxLookups = append(mxLookups, sqlite.LookupResult{
|
|
|
|
|
FirstSeen: v.FirstSeen,
|
|
|
|
|
LastVisit: v.LastVisit,
|
|
|
|
|
Name: v.Name,
|
|
|
|
|
SearchTerm: mxHostname,
|
|
|
|
|
Type: "MX",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-17 10:25:16 -04:00
|
|
|
sqlite.StoreWhoisLookup(mxLookups)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
return mxLookups, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
func (w *DehashedWhoIs) WhoisNS(nsHostname string) ([]sqlite.LookupResult, error) {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois ns search")
|
|
|
|
|
zap.L().Info("whois_ns_debug",
|
|
|
|
|
zap.String("message", "performing whois ns search"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type NSLookup struct {
|
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
|
SearchType string `json:"search_type"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
whoisSearchRequest := NSLookup{
|
|
|
|
|
Domain: nsHostname,
|
2025-05-14 22:00:38 -04:00
|
|
|
SearchType: "reverse-ns",
|
|
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("whois_ns_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.L().Error("whois_ns",
|
|
|
|
|
zap.String("message", "failed to create request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing request")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
zap.L().Info("whois_ns_debug",
|
|
|
|
|
zap.String("message", "performing request"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_ns",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_ns",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, errors.New("response was nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
zap.L().Error("whois_ns",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
|
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("whois_ns",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, &dhErr
|
2025-05-15 16:23:59 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("read response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
zap.L().Info("whois_ns_debug",
|
|
|
|
|
zap.String("message", "read response body"),
|
|
|
|
|
zap.String("body", string(b)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var whois sqlite.WhoIsNSLookup
|
|
|
|
|
err = json.Unmarshal(b, &whois)
|
2025-05-14 22:00:38 -04:00
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to unmarshal response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_ns",
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return nil, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whois.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whois.Data))
|
|
|
|
|
}
|
|
|
|
|
w.balance = whois.RemainingCredits
|
|
|
|
|
var nsLookups []sqlite.LookupResult
|
|
|
|
|
|
|
|
|
|
for _, v := range whois.Data.Result {
|
|
|
|
|
nsLookups = append(nsLookups, sqlite.LookupResult{
|
|
|
|
|
FirstSeen: v.FirstSeen,
|
|
|
|
|
LastVisit: v.LastVisit,
|
|
|
|
|
Name: v.Name,
|
|
|
|
|
SearchTerm: nsHostname,
|
|
|
|
|
Type: "NS",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-17 10:25:16 -04:00
|
|
|
sqlite.StoreWhoisLookup(nsLookups)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
return nsLookups, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
func (w *DehashedWhoIs) WhoisSubdomainScan(domain string) ([]sqlite.SubdomainRecord, error) {
|
2025-05-14 22:00:38 -04:00
|
|
|
var whois sqlite.WhoIsSubdomainScan
|
2025-05-16 15:33:29 -04:00
|
|
|
var subdomains []sqlite.SubdomainRecord
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing whois subdomain scan")
|
|
|
|
|
zap.L().Info("whois_subdomain_scan_debug",
|
|
|
|
|
zap.String("message", "performing whois subdomain scan"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
whoisSearchRequest := DehashedWHOISSearchRequest{
|
|
|
|
|
Domain: domain,
|
|
|
|
|
SearchType: "subdomain-scan",
|
|
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
reqBody, _ := json.Marshal(whoisSearchRequest)
|
2025-05-16 15:33:29 -04:00
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("building request body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Request Body: %v\n", whoisSearchRequest))
|
|
|
|
|
zap.L().Info("whois_subdomain_scan_debug",
|
|
|
|
|
zap.String("message", "building request body"),
|
|
|
|
|
zap.String("body", fmt.Sprintf("%v", whoisSearchRequest)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req, err := http.NewRequest("POST", "https://api.dehashed.com/v2/whois/search", bytes.NewReader(reqBody))
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to create request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_subdomain_scan",
|
|
|
|
|
zap.String("message", "failed to create request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return subdomains, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing request")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", req.Header.Clone()))
|
|
|
|
|
zap.L().Info("whois_subdomain_scan_debug",
|
|
|
|
|
zap.String("message", "performing request"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_subdomain_scan",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return subdomains, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("whois_subdomain_scan",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return subdomains, errors.New("response was nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to read response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("whois_subdomain_scan",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return subdomains, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
|
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("whois_subdomain_scan",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return subdomains, &dhErr
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(b, &whois)
|
|
|
|
|
if err != nil {
|
|
|
|
|
zap.L().Error("whois_subdomain_scan",
|
|
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
fmt.Println("Error unmarshalling response body:", err)
|
|
|
|
|
fmt.Println("Response body:", string(b))
|
2025-05-16 15:33:29 -04:00
|
|
|
return subdomains, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whois.RemainingCredits))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Data: %v\n", whois.Data))
|
|
|
|
|
}
|
|
|
|
|
w.balance = whois.RemainingCredits
|
|
|
|
|
|
|
|
|
|
return whois.Data.Result.Records, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *DehashedWhoIs) Balance() (int, error) {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("getting whois credits")
|
|
|
|
|
zap.L().Info("whois_debug",
|
|
|
|
|
zap.String("message", "getting whois credits"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return w.getBalance()
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
func (w *DehashedWhoIs) getBalance() (int, error) {
|
2025-05-14 22:00:38 -04:00
|
|
|
var whoisCredits sqlite.WhoIsCredits
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", "https://api.dehashed.com/v2/whois/credits", nil)
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to create request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
return whoisCredits.WhoisCredits, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-16 15:33:29 -04:00
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2025-05-16 15:33:29 -04:00
|
|
|
req.Header.Set("Dehashed-Api-Key", w.apiKey)
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("performing request")
|
|
|
|
|
h := req.Header.Clone()
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Headers: %v\n", h))
|
|
|
|
|
zap.L().Info("whois_debug",
|
|
|
|
|
zap.String("message", "performing request"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 22:00:38 -04:00
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
|
|
|
if res != nil {
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to perform request")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("get_whois_credits",
|
|
|
|
|
zap.String("message", "failed to perform request"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisCredits.WhoisCredits, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
if res == nil {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("response was nil")
|
|
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
zap.L().Error("get_whois_credits",
|
|
|
|
|
zap.String("message", "response was nil"),
|
|
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisCredits.WhoisCredits, errors.New("response was nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := io.ReadAll(res.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("failed to read response body")
|
|
|
|
|
debug.PrintError(err)
|
|
|
|
|
}
|
|
|
|
|
zap.L().Error("get_whois_credits",
|
|
|
|
|
zap.String("message", "failed to read response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return whoisCredits.WhoisCredits, err
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
2025-05-15 16:23:59 -04:00
|
|
|
|
|
|
|
|
// Check for HTTP status code errors
|
|
|
|
|
if res.StatusCode != 200 {
|
2025-05-16 15:33:29 -04:00
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("received error status code")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Status Code: %d\n", res.StatusCode))
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
|
|
|
|
}
|
|
|
|
|
dhErr := dehashed.GetDehashedError(res.StatusCode)
|
2025-05-15 16:23:59 -04:00
|
|
|
fmt.Printf("[%d] API Error message: %s\n", res.StatusCode, dhErr.Error())
|
|
|
|
|
zap.L().Error("get_whois_credits",
|
|
|
|
|
zap.String("message", "received error status code"),
|
|
|
|
|
zap.Int("status_code", res.StatusCode),
|
|
|
|
|
zap.String("error", dhErr.Error()),
|
2025-05-16 15:33:29 -04:00
|
|
|
zap.String("body_error", string(b)),
|
2025-05-15 16:23:59 -04:00
|
|
|
)
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisCredits.WhoisCredits, &dhErr
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(b, &whoisCredits)
|
|
|
|
|
if err != nil {
|
|
|
|
|
zap.L().Error("get_whois_credits",
|
|
|
|
|
zap.String("message", "failed to unmarshal response body"),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
fmt.Println("Error unmarshalling response body:", err)
|
|
|
|
|
fmt.Println("Response body:", string(b))
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisCredits.WhoisCredits, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if w.debug {
|
|
|
|
|
debug.PrintInfo("unmarshalled response body")
|
|
|
|
|
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whoisCredits.WhoisCredits))
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-16 15:33:29 -04:00
|
|
|
return whoisCredits.WhoisCredits, nil
|
2025-05-14 22:00:38 -04:00
|
|
|
}
|