mirror of
https://github.com/taygun08/spoof_checker.git
synced 2026-10-10 05:51:51 +00:00
debug mode added + spf macros added
This commit is contained in:
parent
6c8323ff02
commit
2f7b1818d0
1 changed files with 230 additions and 161 deletions
391
spoof_check.go
391
spoof_check.go
|
|
@ -10,10 +10,21 @@ import (
|
|||
"net"
|
||||
"net/http" // New import
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Global debug flag
|
||||
var debugMode bool
|
||||
|
||||
// Debug logs a message if debug mode is enabled
|
||||
func Debug(format string, args ...interface{}) {
|
||||
if debugMode {
|
||||
fmt.Printf("[DEBUG] "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// SPFDMARCRecord contains both SPF and DMARC records for a domain
|
||||
type SPFDMARCRecord struct {
|
||||
domainName string
|
||||
|
|
@ -161,8 +172,115 @@ func getSPFDMARCRecord(domain string) SPFDMARCRecord {
|
|||
return record
|
||||
}
|
||||
|
||||
// Parse SPF record to extract all components
|
||||
func parseSPFRecord(spfRecord string, domainName string) *ParsedSPFRecord {
|
||||
// Reverse an IP address (e.g., "192.168.1.1" -> "1.1.168.192")
|
||||
func reverseIP(ip string) string {
|
||||
parts := strings.Split(ip, ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
return strings.Join(parts, ".")
|
||||
}
|
||||
|
||||
// Expand SPF macros as per RFC 7208
|
||||
func expandSPFMacro(input string, domain string, sender string, ip string) string {
|
||||
// Compute reverse IP if available
|
||||
reverseIPValue := ""
|
||||
if ip != "" {
|
||||
reverseIPValue = reverseIP(ip)
|
||||
}
|
||||
|
||||
// Split sender into local and domain parts
|
||||
localPart := ""
|
||||
domainPart := ""
|
||||
if strings.Contains(sender, "@") {
|
||||
parts := strings.SplitN(sender, "@", 2)
|
||||
localPart = parts[0]
|
||||
domainPart = parts[1]
|
||||
}
|
||||
|
||||
// Define macro replacements
|
||||
replacements := map[string]string{
|
||||
"s": sender,
|
||||
"l": localPart,
|
||||
"o": domainPart,
|
||||
"d": domain,
|
||||
"i": ip,
|
||||
"ir": reverseIPValue, // Reverse IP
|
||||
"v": "in-addr", // IPv4
|
||||
"p": "unknown", // Placeholder for policy domain
|
||||
"c": ip, // Client IP
|
||||
"r": "unknown", // Placeholder for receiver
|
||||
"t": fmt.Sprintf("%d", time.Now().Unix()),
|
||||
}
|
||||
|
||||
// Regex to match macros
|
||||
macroRegex := regexp.MustCompile(`%{([slodipvcrt]|ir)(\d+)?r?}`)
|
||||
|
||||
// Replace macros
|
||||
return macroRegex.ReplaceAllStringFunc(input, func(macro string) string {
|
||||
matches := macroRegex.FindStringSubmatch(macro)
|
||||
if len(matches) < 2 {
|
||||
return macro // Return as-is if no match
|
||||
}
|
||||
key := matches[1]
|
||||
if value, exists := replacements[key]; exists {
|
||||
return value
|
||||
}
|
||||
return macro // Return as-is if no replacement found
|
||||
})
|
||||
}
|
||||
|
||||
// Improved resolveIPFromSPF to try additional methods for IP resolution
|
||||
func resolveIPFromSPF(spfRecord string, domain string) string {
|
||||
// Try the existing mechanisms first
|
||||
mechanisms := strings.Split(spfRecord, " ")
|
||||
for _, mechanism := range mechanisms {
|
||||
if strings.HasPrefix(mechanism, "a") {
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err == nil && len(ips) > 0 {
|
||||
for _, ip := range ips {
|
||||
// Prefer IPv4 addresses
|
||||
if ip.To4() != nil {
|
||||
Debug("Resolved IP from A record: %s", ip.String())
|
||||
return ip.String()
|
||||
}
|
||||
}
|
||||
// If no IPv4, use whatever we have
|
||||
Debug("Resolved IP from A record: %s", ips[0].String())
|
||||
return ips[0].String()
|
||||
}
|
||||
} else if strings.HasPrefix(mechanism, "mx") {
|
||||
// ... existing mx handler code ...
|
||||
} else if strings.HasPrefix(mechanism, "exists:") {
|
||||
// ... existing exists handler code ...
|
||||
}
|
||||
}
|
||||
|
||||
// If no IP was found from mechanisms, try a direct lookup as fallback
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err == nil && len(ips) > 0 {
|
||||
for _, ip := range ips {
|
||||
if ip.To4() != nil {
|
||||
Debug("Resolved IP via direct lookup: %s", ip.String())
|
||||
return ip.String()
|
||||
}
|
||||
}
|
||||
Debug("Resolved IP via direct lookup: %s", ips[0].String())
|
||||
return ips[0].String()
|
||||
}
|
||||
|
||||
// If all else fails, return a dummy IP for debugging
|
||||
Debug("Could not resolve any IP for domain %s", domain)
|
||||
return "127.0.0.1" // Return a dummy IP to prevent empty macros
|
||||
}
|
||||
|
||||
// Parse SPF record to extract all components, including macro expansion
|
||||
func parseSPFRecord(spfRecord string, domainName string, sender string, ip string) *ParsedSPFRecord {
|
||||
// Dynamically resolve IP if not provided
|
||||
if ip == "" {
|
||||
ip = resolveIPFromSPF(spfRecord, domainName)
|
||||
}
|
||||
|
||||
parsedRecord := &ParsedSPFRecord{
|
||||
aRecord: make([]string, 0),
|
||||
includeRecords: make([]ParsedIncludeRecord, 0),
|
||||
|
|
@ -179,23 +297,20 @@ func parseSPFRecord(spfRecord string, domainName string) *ParsedSPFRecord {
|
|||
visitedDomains := make(map[string]bool)
|
||||
visitedDomains[domainName] = true
|
||||
|
||||
return parseSPFRecordWithDepth(spfRecord, domainName, visitedDomains, 0)
|
||||
Debug("Starting SPF parsing for domain: %s", domainName)
|
||||
return parseSPFRecordWithDepth(spfRecord, domainName, sender, ip, visitedDomains, 0)
|
||||
}
|
||||
|
||||
// Helper function with depth tracking to prevent stack overflow
|
||||
func parseSPFRecordWithDepth(spfRecord string, domainName string, visitedDomains map[string]bool, depth int) *ParsedSPFRecord {
|
||||
func parseSPFRecordWithDepth(spfRecord string, domainName string, sender string, ip string, visitedDomains map[string]bool, depth int) *ParsedSPFRecord {
|
||||
// Limit recursion depth
|
||||
maxDepth := 10
|
||||
if depth > maxDepth {
|
||||
return &ParsedSPFRecord{
|
||||
aRecord: make([]string, 0),
|
||||
includeRecords: make([]ParsedIncludeRecord, 0),
|
||||
mxRecord: make([]string, 0),
|
||||
existsRecords: make([]string, 0),
|
||||
ptrRecords: make([]string, 0),
|
||||
}
|
||||
Debug("Max recursion depth reached for domain: %s", domainName)
|
||||
return &ParsedSPFRecord{}
|
||||
}
|
||||
|
||||
Debug("Parsing SPF record for domain: %s, depth: %d", domainName, depth)
|
||||
parsedRecord := &ParsedSPFRecord{
|
||||
aRecord: make([]string, 0),
|
||||
includeRecords: make([]ParsedIncludeRecord, 0),
|
||||
|
|
@ -204,62 +319,60 @@ func parseSPFRecordWithDepth(spfRecord string, domainName string, visitedDomains
|
|||
ptrRecords: make([]string, 0),
|
||||
}
|
||||
|
||||
if isNullOrWhiteSpace(spfRecord) {
|
||||
return parsedRecord
|
||||
}
|
||||
|
||||
mechanisms := strings.Split(spfRecord, " ")
|
||||
for _, mechanism := range mechanisms {
|
||||
if strings.HasPrefix(mechanism, "a:") || mechanism == "a" {
|
||||
parsedRecord.aRecord = append(parsedRecord.aRecord, mechanism)
|
||||
} else if strings.HasPrefix(mechanism, "include:") {
|
||||
includeDomain := strings.TrimPrefix(mechanism, "include:")
|
||||
includeRecord := ParsedIncludeRecord{
|
||||
includeRecord: includeDomain,
|
||||
expandedMechanism := expandSPFMacro(mechanism, domainName, sender, ip)
|
||||
Debug("Expanded mechanism: %s", expandedMechanism)
|
||||
|
||||
if strings.HasPrefix(expandedMechanism, "a:") || expandedMechanism == "a" {
|
||||
parsedRecord.aRecord = append(parsedRecord.aRecord, expandedMechanism)
|
||||
} else if strings.HasPrefix(expandedMechanism, "include:") {
|
||||
includeDomain := strings.TrimPrefix(expandedMechanism, "include:")
|
||||
Debug("Processing include: %s", includeDomain)
|
||||
|
||||
if visitedDomains[includeDomain] {
|
||||
Debug("Loop detected for include: %s", includeDomain)
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip already visited domains to prevent loops
|
||||
if !visitedDomains[includeDomain] {
|
||||
visitedDomains[includeDomain] = true
|
||||
visitedDomains[includeDomain] = true
|
||||
includeSPF := getSPFDMARCRecord(includeDomain)
|
||||
if !isNullOrWhiteSpace(includeSPF.spfRecord) {
|
||||
subParsed := parseSPFRecordWithDepth(includeSPF.spfRecord, includeDomain, sender, ip, visitedDomains, depth+1)
|
||||
parsedRecord.includeRecords = append(parsedRecord.includeRecords, ParsedIncludeRecord{
|
||||
includeRecord: includeDomain,
|
||||
subLookup: subParsed,
|
||||
})
|
||||
}
|
||||
} else if strings.HasPrefix(expandedMechanism, "mx:") || expandedMechanism == "mx" {
|
||||
parsedRecord.mxRecord = append(parsedRecord.mxRecord, expandedMechanism)
|
||||
} else if strings.HasPrefix(expandedMechanism, "exists:") {
|
||||
parsedRecord.existsRecords = append(parsedRecord.existsRecords, expandedMechanism)
|
||||
} else if strings.HasPrefix(expandedMechanism, "ptr:") || expandedMechanism == "ptr" {
|
||||
parsedRecord.ptrRecords = append(parsedRecord.ptrRecords, expandedMechanism)
|
||||
} else if strings.HasPrefix(expandedMechanism, "redirect=") {
|
||||
redirectDomain := strings.TrimPrefix(expandedMechanism, "redirect=")
|
||||
Debug("Processing redirect to: %s", redirectDomain)
|
||||
|
||||
// Get the SPF record for the included domain
|
||||
includedSPF := getSPFDMARCRecord(includeDomain)
|
||||
if !isNullOrWhiteSpace(includedSPF.spfRecord) {
|
||||
includeRecord.subLookup = parseSPFRecordWithDepth(includedSPF.spfRecord, includeDomain, visitedDomains, depth+1)
|
||||
}
|
||||
if visitedDomains[redirectDomain] {
|
||||
Debug("Loop detected for redirect: %s", redirectDomain)
|
||||
continue
|
||||
}
|
||||
|
||||
parsedRecord.includeRecords = append(parsedRecord.includeRecords, includeRecord)
|
||||
} else if strings.HasPrefix(mechanism, "mx:") || mechanism == "mx" {
|
||||
parsedRecord.mxRecord = append(parsedRecord.mxRecord, mechanism)
|
||||
} else if strings.HasPrefix(mechanism, "exists:") {
|
||||
parsedRecord.existsRecords = append(parsedRecord.existsRecords, mechanism)
|
||||
} else if strings.HasPrefix(mechanism, "ptr:") || mechanism == "ptr" {
|
||||
parsedRecord.ptrRecords = append(parsedRecord.ptrRecords, mechanism)
|
||||
}
|
||||
// Check for redirect
|
||||
if strings.HasPrefix(mechanism, "redirect=") {
|
||||
redirectDomain := strings.TrimPrefix(mechanism, "redirect=")
|
||||
|
||||
// Skip already visited domains to prevent loops
|
||||
if !visitedDomains[redirectDomain] {
|
||||
visitedDomains[redirectDomain] = true
|
||||
|
||||
redirectSPF := getSPFDMARCRecord(redirectDomain)
|
||||
if !isNullOrWhiteSpace(redirectSPF.spfRecord) {
|
||||
// Parse the redirected SPF record
|
||||
redirectParsed := parseSPFRecordWithDepth(redirectSPF.spfRecord, redirectDomain, visitedDomains, depth+1)
|
||||
// Merge the parsed records
|
||||
parsedRecord.aRecord = append(parsedRecord.aRecord, redirectParsed.aRecord...)
|
||||
parsedRecord.includeRecords = append(parsedRecord.includeRecords, redirectParsed.includeRecords...)
|
||||
parsedRecord.mxRecord = append(parsedRecord.mxRecord, redirectParsed.mxRecord...)
|
||||
parsedRecord.existsRecords = append(parsedRecord.existsRecords, redirectParsed.existsRecords...)
|
||||
parsedRecord.ptrRecords = append(parsedRecord.ptrRecords, redirectParsed.ptrRecords...)
|
||||
}
|
||||
visitedDomains[redirectDomain] = true
|
||||
redirectSPF := getSPFDMARCRecord(redirectDomain)
|
||||
if !isNullOrWhiteSpace(redirectSPF.spfRecord) {
|
||||
redirectParsed := parseSPFRecordWithDepth(redirectSPF.spfRecord, redirectDomain, sender, ip, visitedDomains, depth+1)
|
||||
parsedRecord.aRecord = append(parsedRecord.aRecord, redirectParsed.aRecord...)
|
||||
parsedRecord.includeRecords = append(parsedRecord.includeRecords, redirectParsed.includeRecords...)
|
||||
parsedRecord.mxRecord = append(parsedRecord.mxRecord, redirectParsed.mxRecord...)
|
||||
parsedRecord.existsRecords = append(parsedRecord.existsRecords, redirectParsed.existsRecords...)
|
||||
parsedRecord.ptrRecords = append(parsedRecord.ptrRecords, redirectParsed.ptrRecords...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug("Finished parsing SPF record for domain: %s, depth: %d", domainName, depth)
|
||||
return parsedRecord
|
||||
}
|
||||
|
||||
|
|
@ -697,8 +810,8 @@ func main() {
|
|||
var jsonOutput bool
|
||||
var outputFile string
|
||||
var inputFile string
|
||||
var checkSubTakeover bool // New flag
|
||||
|
||||
var checkSubTakeover bool // New flag
|
||||
flag.BoolVar(&debugMode, "debug", false, "Enable debug mode") // New debug flag
|
||||
flag.StringVar(&domain, "domain", "", "Domain to check for spoofing vulnerabilities")
|
||||
flag.BoolVar(&interactive, "interactive", false, "Run in interactive mode")
|
||||
flag.BoolVar(&jsonOutput, "json", false, "Output results in JSON format")
|
||||
|
|
@ -707,6 +820,10 @@ func main() {
|
|||
flag.BoolVar(&checkSubTakeover, "subtakeover", false, "Check for subdomain takeover vulnerabilities")
|
||||
flag.Parse()
|
||||
|
||||
Debug("Debug mode enabled")
|
||||
Debug("Parsed flags: domain=%s, interactive=%v, jsonOutput=%v, outputFile=%s, inputFile=%s, checkSubTakeover=%v",
|
||||
domain, interactive, jsonOutput, outputFile, inputFile, checkSubTakeover)
|
||||
|
||||
// Process domains from input file if specified
|
||||
if inputFile != "" {
|
||||
processDomainFile(inputFile, jsonOutput, outputFile, checkSubTakeover)
|
||||
|
|
@ -733,6 +850,8 @@ func main() {
|
|||
|
||||
// Process a file containing a list of domains
|
||||
func processDomainFile(inputFile string, jsonOutput bool, outputFile string, checkSubTakeover bool) {
|
||||
Debug("Processing input file: %s", inputFile)
|
||||
|
||||
// Read the file
|
||||
file, err := os.Open(inputFile)
|
||||
if err != nil {
|
||||
|
|
@ -768,109 +887,10 @@ func processDomainFile(inputFile string, jsonOutput bool, outputFile string, che
|
|||
continue // Skip empty lines and comments
|
||||
}
|
||||
|
||||
Debug("Processing domain: %s", domain)
|
||||
|
||||
// Process the domain
|
||||
fmt.Printf("Processing domain: %s\n", domain)
|
||||
|
||||
// Get SPF and DMARC records
|
||||
spfDmarcRecord := getSPFDMARCRecord(domain)
|
||||
|
||||
// Parse SPF record
|
||||
parsedSPF := parseSPFRecord(spfDmarcRecord.spfRecord, domain)
|
||||
|
||||
// Scan for issues
|
||||
engine := &IssueEngine{}
|
||||
issues := engine.IssueScan(spfDmarcRecord, parsedSPF)
|
||||
|
||||
// Check for subdomain takeover if flag is enabled
|
||||
var takeoverResult *SubdomainTakeoverResult
|
||||
if checkSubTakeover {
|
||||
result := checkSubdomainTakeover(domain)
|
||||
takeoverResult = &result
|
||||
}
|
||||
|
||||
// Format the output
|
||||
var result string
|
||||
if jsonOutput {
|
||||
// Convert to JSON
|
||||
jsonResult := issuestoJSON(domain, spfDmarcRecord, issues)
|
||||
|
||||
// Add takeover result if available
|
||||
if takeoverResult != nil {
|
||||
jsonResult.TakeoverResults = takeoverResult
|
||||
}
|
||||
|
||||
jsonData, err := json.MarshalIndent(jsonResult, "", " ")
|
||||
if err != nil {
|
||||
result = fmt.Sprintf("{\"success\": false, \"message\": \"Error generating JSON: %s\"}\n", err)
|
||||
} else {
|
||||
result = string(jsonData)
|
||||
}
|
||||
|
||||
// For file output, add to all results
|
||||
if outputFile != "" {
|
||||
// Write to the file with appropriate comma
|
||||
if domainCount > 0 {
|
||||
outFile.WriteString(",\n")
|
||||
}
|
||||
outFile.WriteString(result)
|
||||
} else {
|
||||
// Print to console
|
||||
fmt.Println(result)
|
||||
}
|
||||
} else {
|
||||
// Format as text
|
||||
var builder strings.Builder
|
||||
builder.WriteString(fmt.Sprintf("\n--- Checking domain: %s ---\n", domain))
|
||||
builder.WriteString(fmt.Sprintf("SPF Record: %s\n", spfDmarcRecord.spfRecord))
|
||||
builder.WriteString(fmt.Sprintf("DMARC Record: %s\n\n", spfDmarcRecord.dmarcRecord))
|
||||
|
||||
if len(issues) == 0 {
|
||||
builder.WriteString("No issues found. The domain is well protected against spoofing.\n")
|
||||
} else {
|
||||
builder.WriteString("Found the following issues:\n")
|
||||
for _, issue := range issues {
|
||||
builder.WriteString(fmt.Sprintf("\nCode %d: %s\n", issue.code, issue.title))
|
||||
builder.WriteString(fmt.Sprintf(" Severity: %s\n", issue.severity))
|
||||
builder.WriteString(fmt.Sprintf(" Detail: %s\n", issue.detail))
|
||||
}
|
||||
}
|
||||
|
||||
// Add subdomain takeover results if enabled
|
||||
if takeoverResult != nil {
|
||||
builder.WriteString("\n--- Subdomain Takeover Check ---\n")
|
||||
if takeoverResult.Vulnerable {
|
||||
builder.WriteString(fmt.Sprintf("VULNERABLE to subdomain takeover!\n"))
|
||||
builder.WriteString(fmt.Sprintf("Service: %s\n", takeoverResult.Service))
|
||||
if takeoverResult.CnameRecord != "" {
|
||||
builder.WriteString(fmt.Sprintf("CNAME: %s\n", takeoverResult.CnameRecord))
|
||||
}
|
||||
if takeoverResult.Fingerprint != "" {
|
||||
builder.WriteString(fmt.Sprintf("Matching Fingerprint: %s\n", takeoverResult.Fingerprint))
|
||||
}
|
||||
if takeoverResult.ResponseBody != "" {
|
||||
builder.WriteString(fmt.Sprintf("Response snippet: %s\n", takeoverResult.ResponseBody))
|
||||
}
|
||||
} else {
|
||||
builder.WriteString("Not vulnerable to subdomain takeover.\n")
|
||||
if takeoverResult.ErrorMessage != "" {
|
||||
builder.WriteString(fmt.Sprintf("Note: %s\n", takeoverResult.ErrorMessage))
|
||||
}
|
||||
if takeoverResult.CnameRecord != "" {
|
||||
builder.WriteString(fmt.Sprintf("CNAME: %s\n", takeoverResult.CnameRecord))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.WriteString("\n--- End of report ---\n")
|
||||
result = builder.String()
|
||||
|
||||
// If output file specified, write to it; otherwise print to console
|
||||
if outputFile != "" {
|
||||
outFile.WriteString(result)
|
||||
} else {
|
||||
fmt.Print(result)
|
||||
}
|
||||
}
|
||||
checkDomain(domain, jsonOutput, outputFile, checkSubTakeover)
|
||||
|
||||
domainCount++
|
||||
}
|
||||
|
|
@ -885,6 +905,7 @@ func processDomainFile(inputFile string, jsonOutput bool, outputFile string, che
|
|||
outFile.WriteString("\n]")
|
||||
}
|
||||
|
||||
Debug("Processed %d domains from %s", domainCount, inputFile)
|
||||
fmt.Printf("Processed %d domains from %s\n", domainCount, inputFile)
|
||||
if outputFile != "" {
|
||||
fmt.Printf("Results saved to %s\n", outputFile)
|
||||
|
|
@ -919,22 +940,70 @@ func issuestoJSON(domain string, spfDmarcRecord SPFDMARCRecord, issues []IssueSc
|
|||
return result
|
||||
}
|
||||
|
||||
// Modified function to also display SPF record content for each domain
|
||||
func DebugSPFRecord(prefix string, record *ParsedSPFRecord, domainName string, spfText string) {
|
||||
if record == nil {
|
||||
Debug("%sNil SPF Record", prefix)
|
||||
return
|
||||
}
|
||||
|
||||
// Display the domain name and its SPF record at the top level
|
||||
if domainName != "" && spfText != "" {
|
||||
Debug("%sDomain: %s", prefix, domainName)
|
||||
Debug("%sSPF Record: %s", prefix, spfText)
|
||||
}
|
||||
|
||||
Debug("%sA Records: %v", prefix, record.aRecord)
|
||||
Debug("%sMX Records: %v", prefix, record.mxRecord)
|
||||
Debug("%sExists Records: %v", prefix, record.existsRecords)
|
||||
Debug("%sPTR Records: %v", prefix, record.ptrRecords)
|
||||
|
||||
if len(record.includeRecords) > 0 {
|
||||
Debug("%sIncludes (%d):", prefix, len(record.includeRecords))
|
||||
for i, include := range record.includeRecords {
|
||||
Debug("%s [%d] Domain: %s", prefix, i, include.includeRecord)
|
||||
if include.subLookup != nil {
|
||||
Debug("%s [%d] SubLookup:", prefix, i)
|
||||
|
||||
// Get the SPF record for this included domain
|
||||
includeSPF := getSPFDMARCRecord(include.includeRecord)
|
||||
DebugSPFRecord(prefix+" ", include.subLookup, include.includeRecord, includeSPF.spfRecord)
|
||||
} else {
|
||||
Debug("%s [%d] SubLookup: nil", prefix, i)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Debug("%sNo includes", prefix)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the checkDomain function to use the enhanced debug function
|
||||
func checkDomain(domain string, jsonOutput bool, outputFile string, checkSubTakeover bool) {
|
||||
Debug("Checking domain: %s", domain)
|
||||
|
||||
// Get SPF and DMARC records
|
||||
spfDmarcRecord := getSPFDMARCRecord(domain)
|
||||
Debug("Retrieved SPF record: %s", spfDmarcRecord.spfRecord)
|
||||
Debug("Retrieved DMARC record: %s", spfDmarcRecord.dmarcRecord)
|
||||
|
||||
// Parse SPF record
|
||||
parsedSPF := parseSPFRecord(spfDmarcRecord.spfRecord, domain)
|
||||
parsedSPF := parseSPFRecord(spfDmarcRecord.spfRecord, domain, "", "")
|
||||
|
||||
// Use our enhanced debug function to print the parsed SPF record
|
||||
Debug("Parsed SPF record structure:")
|
||||
DebugSPFRecord(" ", parsedSPF, domain, spfDmarcRecord.spfRecord)
|
||||
|
||||
// Scan for issues
|
||||
engine := &IssueEngine{}
|
||||
issues := engine.IssueScan(spfDmarcRecord, parsedSPF)
|
||||
Debug("Identified issues: %+v", issues)
|
||||
|
||||
// Check for subdomain takeover if flag is enabled
|
||||
var takeoverResult *SubdomainTakeoverResult
|
||||
if checkSubTakeover {
|
||||
result := checkSubdomainTakeover(domain)
|
||||
takeoverResult = &result
|
||||
Debug("Subdomain takeover result: %+v", takeoverResult)
|
||||
}
|
||||
|
||||
var output string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue