254 lines
6.4 KiB
Go
254 lines
6.4 KiB
Go
package operations
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"service-operation/types"
|
|
)
|
|
|
|
type DNSOperation struct {
|
|
timeout time.Duration
|
|
}
|
|
|
|
func NewDNSOperation(timeout time.Duration) *DNSOperation {
|
|
return &DNSOperation{timeout: timeout}
|
|
}
|
|
|
|
func (d *DNSOperation) Execute(host, query string) (*types.OperationResult, error) {
|
|
// Validate inputs
|
|
if host == "" {
|
|
return nil, fmt.Errorf("host cannot be empty")
|
|
}
|
|
|
|
if query == "" {
|
|
query = "A" // Default to A record
|
|
}
|
|
|
|
result := &types.OperationResult{
|
|
Type: types.OperationDNS,
|
|
Host: host,
|
|
DNSType: query,
|
|
StartTime: time.Now(),
|
|
}
|
|
|
|
start := time.Now()
|
|
|
|
// Resolve the host first to get detailed info
|
|
var resolvedIPs []string
|
|
var err error
|
|
|
|
switch strings.ToUpper(query) {
|
|
case "A":
|
|
resolvedIPs, err = d.performARecordLookup(host)
|
|
|
|
case "AAAA":
|
|
resolvedIPs, err = d.performAAAARecordLookup(host)
|
|
|
|
case "MX":
|
|
resolvedIPs, err = d.performMXRecordLookup(host)
|
|
|
|
case "TXT":
|
|
resolvedIPs, err = d.performTXTRecordLookup(host)
|
|
|
|
case "CNAME":
|
|
resolvedIPs, err = d.performCNAMERecordLookup(host)
|
|
|
|
case "NS":
|
|
resolvedIPs, err = d.performNSRecordLookup(host)
|
|
|
|
default:
|
|
// Default to A record lookup for unknown types
|
|
resolvedIPs, err = d.performARecordLookup(host)
|
|
}
|
|
|
|
result.ResponseTime = time.Since(start)
|
|
result.EndTime = time.Now()
|
|
|
|
if err != nil {
|
|
result.Error = err.Error()
|
|
result.Success = false
|
|
result.Details = d.createDetailedErrorMessage(err.Error(), host, query)
|
|
} else {
|
|
result.DNSRecords = resolvedIPs
|
|
result.Success = len(resolvedIPs) > 0
|
|
|
|
if result.Success {
|
|
result.Details = d.createDetailedSuccessMessage(result, host, query, resolvedIPs)
|
|
} else {
|
|
result.Error = "No DNS records found"
|
|
result.Details = d.createDetailedErrorMessage("no records found", host, query)
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (d *DNSOperation) performARecordLookup(host string) ([]string, error) {
|
|
ips, err := net.LookupIP(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ipv4Records []string
|
|
for _, ip := range ips {
|
|
if ipv4 := ip.To4(); ipv4 != nil {
|
|
ipv4Records = append(ipv4Records, ipv4.String())
|
|
}
|
|
}
|
|
|
|
return ipv4Records, nil
|
|
}
|
|
|
|
func (d *DNSOperation) performAAAARecordLookup(host string) ([]string, error) {
|
|
ips, err := net.LookupIP(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ipv6Records []string
|
|
for _, ip := range ips {
|
|
if ipv6 := ip.To16(); ipv6 != nil && ip.To4() == nil {
|
|
ipv6Records = append(ipv6Records, ipv6.String())
|
|
}
|
|
}
|
|
|
|
return ipv6Records, nil
|
|
}
|
|
|
|
func (d *DNSOperation) performMXRecordLookup(host string) ([]string, error) {
|
|
mxRecords, err := net.LookupMX(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var records []string
|
|
for _, mx := range mxRecords {
|
|
records = append(records, fmt.Sprintf("%s (priority: %d)", mx.Host, mx.Pref))
|
|
}
|
|
|
|
return records, nil
|
|
}
|
|
|
|
func (d *DNSOperation) performTXTRecordLookup(host string) ([]string, error) {
|
|
txtRecords, err := net.LookupTXT(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return txtRecords, nil
|
|
}
|
|
|
|
func (d *DNSOperation) performCNAMERecordLookup(host string) ([]string, error) {
|
|
cname, err := net.LookupCNAME(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []string{cname}, nil
|
|
}
|
|
|
|
func (d *DNSOperation) performNSRecordLookup(host string) ([]string, error) {
|
|
nsRecords, err := net.LookupNS(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var records []string
|
|
for _, ns := range nsRecords {
|
|
records = append(records, ns.Host)
|
|
}
|
|
|
|
return records, nil
|
|
}
|
|
|
|
func (d *DNSOperation) createDetailedSuccessMessage(result *types.OperationResult, host, queryType string, records []string) string {
|
|
var details strings.Builder
|
|
|
|
// Success indicator with basic info
|
|
details.WriteString(fmt.Sprintf("🟢 DNS SUCCESS - %s query for %s",
|
|
strings.ToUpper(queryType), host))
|
|
|
|
// Response time
|
|
details.WriteString(fmt.Sprintf(" | Response time: %.2fms",
|
|
float64(result.ResponseTime.Nanoseconds())/1000000))
|
|
|
|
// Record count
|
|
details.WriteString(fmt.Sprintf(" | Records found: %d", len(records)))
|
|
|
|
// Show first few records for context
|
|
if len(records) > 0 {
|
|
details.WriteString(" | ")
|
|
if len(records) <= 3 {
|
|
details.WriteString(fmt.Sprintf("Results: %s", strings.Join(records, ", ")))
|
|
} else {
|
|
details.WriteString(fmt.Sprintf("Results: %s... (+%d more)",
|
|
strings.Join(records[:3], ", "), len(records)-3))
|
|
}
|
|
}
|
|
|
|
return details.String()
|
|
}
|
|
|
|
func (d *DNSOperation) createDetailedErrorMessage(errorMsg, host, queryType string) string {
|
|
var details strings.Builder
|
|
|
|
errorLower := strings.ToLower(errorMsg)
|
|
|
|
if strings.Contains(errorLower, "timeout") {
|
|
details.WriteString("⏱️ DNS TIMEOUT - Query timed out")
|
|
} else if strings.Contains(errorLower, "no such host") || strings.Contains(errorLower, "host not found") {
|
|
details.WriteString("🔍 HOST NOT FOUND - DNS resolution failed")
|
|
} else if strings.Contains(errorLower, "no answer") || strings.Contains(errorLower, "no records found") {
|
|
details.WriteString("📝 NO RECORDS - No DNS records of requested type")
|
|
} else if strings.Contains(errorLower, "server failure") {
|
|
details.WriteString("🔧 SERVER FAILURE - DNS server error")
|
|
} else if strings.Contains(errorLower, "refused") {
|
|
details.WriteString("🚫 QUERY REFUSED - DNS server refused query")
|
|
} else {
|
|
details.WriteString("❌ DNS FAILED - Query error")
|
|
}
|
|
|
|
// Add query details
|
|
details.WriteString(fmt.Sprintf(" | Query: %s %s",
|
|
strings.ToUpper(queryType), host))
|
|
|
|
// Add specific error details
|
|
if errorMsg != "" {
|
|
details.WriteString(fmt.Sprintf(" | Error: %s", d.getShortErrorMessage(errorMsg)))
|
|
}
|
|
|
|
return details.String()
|
|
}
|
|
|
|
func (d *DNSOperation) getShortErrorMessage(errorMessage string) string {
|
|
if errorMessage == "" {
|
|
return "Unknown error"
|
|
}
|
|
|
|
errorLower := strings.ToLower(errorMessage)
|
|
|
|
if strings.Contains(errorLower, "timeout") {
|
|
return "Query timeout"
|
|
} else if strings.Contains(errorLower, "no such host") {
|
|
return "Host not found"
|
|
} else if strings.Contains(errorLower, "no answer") {
|
|
return "No records found"
|
|
} else if strings.Contains(errorLower, "server failure") {
|
|
return "DNS server failure"
|
|
} else if strings.Contains(errorLower, "refused") {
|
|
return "Query refused"
|
|
} else if strings.Contains(errorLower, "network unreachable") {
|
|
return "Network unreachable"
|
|
}
|
|
|
|
// For other errors, take first 50 characters and clean it up
|
|
shortMsg := errorMessage
|
|
if len(shortMsg) > 50 {
|
|
shortMsg = shortMsg[:50] + "..."
|
|
}
|
|
|
|
return shortMsg
|
|
} |