Skip to content

Commit

Permalink
domain gen engine
Browse files Browse the repository at this point in the history
  • Loading branch information
mattbr0wn authored and alexopenline committed Nov 14, 2024
1 parent a5746b0 commit c9346cd
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 0 deletions.
204 changes: 204 additions & 0 deletions domaingen/domain_recommendations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package domaingen

import (
"context"
"fmt"
"net"
"os/exec"
"strings"
"time"
)

// checkDomain checks if a domain is likely available using multiple methods
func IsDomainAvailable(domain string) (ok, available bool) {
// First try DNS lookup
dnsOk, dnsCheck := dnsCheck(domain)
if dnsCheck {
return true, false
}

whoOk, whoCheck := checkWhois(domain)

if !dnsOk && !whoOk {
return false, false
}

if whoCheck {
return true, false
}

return true, true
}

func RecommendOutboundDomains(domainRoot string, count int) []string {
var results []string
c := 0
pre := getDomainPrefix()
suf := getDomainSuffix()

for _, prefix := range pre {
if c == count {
return results
}
newDomain := fmt.Sprintf("%s%s%s", prefix, domainRoot, ".com")
_, avaliable := IsDomainAvailable(newDomain)
if avaliable {
c++
results = append(results, newDomain)
}
}

for _, suffix := range suf {
if c == count {
return results
}
newDomain := fmt.Sprintf("%s%s%s", domainRoot, suffix, ".com")
_, available := IsDomainAvailable(newDomain)
if available {
c++
results = append(results, newDomain)
}
}

for _, prefix := range pre {
for _, suffix := range suf {
if c == count {
return results
}
newDomain := fmt.Sprintf("%s%s%s%s", prefix, domainRoot, suffix, ".com")
_, available := IsDomainAvailable(newDomain)
if available {
c++
results = append(results, newDomain)
}
}
}

return results
}

func dnsCheck(domain string) (ok bool, exists bool) {
ips, err := net.LookupIP(domain)
if len(ips) > 0 {
return true, true
}

if err != nil && strings.Contains(err.Error(), "no such host") {
return true, false
}

if err != nil {
return false, false
}

return true, false
}

// checkWhois runs a whois query and analyzes the output
func checkWhois(domain string) (ok, exists bool) {
// Create a context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

// Create the command with context
cmd := exec.CommandContext(ctx, "whois", domain)

// Create a pipe for stdout
output, err := cmd.Output()

// Check if the context deadline exceeded
if ctx.Err() == context.DeadlineExceeded {
return false, false
}

if err != nil {
// Check if it's an exit error (whois sometimes exits with status 1)
if exitErr, ok := err.(*exec.ExitError); ok {
// Still process the output if we got any
if len(exitErr.Stderr) > 0 {
output = exitErr.Stderr
}
} else {
return false, false
}
}

response := strings.ToLower(string(output))

// Common phrases indicating domain is available
availablePhrases := []string{
"no match for",
"not found",
"no entries found",
"no data found",
"domain not found",
"status: free",
"status: available",
}

// Common phrases indicating domain is taken
takenPhrases := []string{
"domain name:",
"registrar:",
"creation date:",
"registered on:",
"status: active",
}

// Check for availability indicators
for _, phrase := range availablePhrases {
if strings.Contains(response, phrase) {
return true, false
}
}

// Check for registered indicators
for _, phrase := range takenPhrases {
if strings.Contains(response, phrase) {
return true, true
}
}

return true, false
}

func getDomainSuffix() []string {
suffix := []string{
"ai",
"hq",
"io",
"ly",
"app",
"dev",
"api",
"hub",
"now",
"tech",
"labs",
"zone",
"team",
"tools",
"cloud",
"software",
"platform",
}
return suffix
}

func getDomainPrefix() []string {
prefix := []string{
"go",
"by",
"at",
"get",
"try",
"try",
"use",
"run",
"meet",
"join",
"from",
"with",
}
return prefix
}
6 changes: 6 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/customeros/mailsherpa/cli"
"github.com/customeros/mailsherpa/domaincheck"
"github.com/customeros/mailsherpa/domaingen"
"github.com/customeros/mailsherpa/emailparser"
)

Expand All @@ -14,6 +15,9 @@ func main() {
args := flag.Args()

switch args[0] {
case "avail":
_, avail := domaingen.IsDomainAvailable(args[1])
fmt.Println("Domain Available:", avail)
case "domain":
if len(args) != 2 {
fmt.Println("Usage: mailsherpa domain <domain>")
Expand All @@ -26,6 +30,8 @@ func main() {
return
}
cli.VerifySyntax(args[1], true)
case "rec":
fmt.Println(domaingen.RecommendOutboundDomains(args[1], 20))
case "redirect":
fmt.Println(domaincheck.PrimaryDomainCheck(args[1]))
case "parse":
Expand Down

0 comments on commit c9346cd

Please sign in to comment.