Skip to content

Commit

Permalink
feat: introduce strict mode domain relation where TLDs must match for…
Browse files Browse the repository at this point in the history
… two domains to be related
  • Loading branch information
stuchl4n3k committed Jul 24, 2023
1 parent d72b096 commit c1e7970
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 82 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,17 @@ This will also download the latest GeoIP database (IPLocation-lite).
### Usage

```bash
udig [-h|--help] [-v|--version] [-V|--verbose] [--json] [-d|--domain "<value>"]
udig [-h|--help] [-v|--version] [-V|--verbose] [-s|--strict] [--json]
[-d|--domain "<value>" [-d|--domain "<value>" ...]]

ÜberDig - dig on steroids v1.3 by stuchl4n3k
ÜberDig - dig on steroids v1.4 by stuchl4n3k

Arguments:

-h --help Print help information
-v --version Print version and exit
-V --verbose Be more verbose
-s --strict Strict domain relation (TLD match)
--json Output payloads as JSON objects
-d --domain Domain to resolve
```
Expand Down
12 changes: 9 additions & 3 deletions cmd/udig/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ package main
import (
"encoding/json"
"fmt"
"net/url"
"os"

"github.com/akamensky/argparse"
"github.com/miekg/dns"
"github.com/netrixone/udig"
"net/url"
"os"
)

const (
prog = "udig"
version = "1.3"
version = "1.4"
author = "stuchl4n3k"
description = "ÜberDig - dig on steroids v" + version + " by " + author
)
Expand Down Expand Up @@ -103,6 +104,7 @@ func main() {
parser := argparse.NewParser(prog, description)
printVersion := parser.Flag("v", "version", &argparse.Options{Required: false, Help: "Print version and exit"})
beVerbose := parser.Flag("V", "verbose", &argparse.Options{Required: false, Help: "Be more verbose"})
beStrict := parser.Flag("s", "strict", &argparse.Options{Required: false, Help: "Strict domain relation (TLD match)"})
jsonOutput := parser.Flag("", "json", &argparse.Options{Required: false, Help: "Output payloads as JSON objects"})
domain := parser.String("d", "domain", &argparse.Options{Required: false, Help: "Domain to resolve"})

Expand All @@ -126,6 +128,10 @@ func main() {
udig.LogLevel = udig.LogLevelInfo
}

if *beStrict {
udig.IsDomainRelated = udig.StrictDomainRelation
}

outputJson = *jsonOutput

fmt.Println(banner)
Expand Down
68 changes: 0 additions & 68 deletions dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,74 +294,6 @@ func Test_parentDomainOf_By_TLD(t *testing.T) {
assert.Empty(t, parent)
}

func Test_isDomainRelated_By_same_domain(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := domainA

// Execute.
res1 := isDomainRelated(domainA, domainB)
res2 := isDomainRelated(domainB, domainA)

// Assert.
assert.Equal(t, true, res1)
assert.Equal(t, true, res2)
}

func Test_isDomainRelated_By_subdomain(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := "sub.example.com"

// Execute.
res1 := isDomainRelated(domainA, domainB)
res2 := isDomainRelated(domainB, domainA)

// Assert.
assert.Equal(t, true, res1)
assert.Equal(t, true, res2)
}

func Test_isDomainRelated_By_domain_with_different_TLD(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := "sub.example.net"

// Execute.
res1 := isDomainRelated(domainA, domainB)
res2 := isDomainRelated(domainB, domainA)

// Assert.
assert.Equal(t, true, res1)
assert.Equal(t, true, res2)
}

func Test_isDomainRelated_By_TLDs(t *testing.T) {
// Setup.
domainA := "com"
domainB := "com"

// Execute.
res := isDomainRelated(domainA, domainB)

// Assert.
assert.Equal(t, false, res)
}

func Test_isDomainRelated_By_invalid_domain(t *testing.T) {
// Setup.
domainA := "."
domainB := "example.com"

// Execute.
res1 := isDomainRelated(domainA, domainB)
res2 := isDomainRelated(domainB, domainA)

// Assert.
assert.Equal(t, false, res1)
assert.Equal(t, false, res2)
}

func mockDNSResponse(qType uint16, numRecords int) *dns.Msg {
msg := &dns.Msg{}

Expand Down
2 changes: 1 addition & 1 deletion udig.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func (udig *udigImpl) isCnameOrRelated(nextDomain string, resolution Resolution)
}

// Otherwise try heuristics.
return isDomainRelated(nextDomain, resolution.Query())
return IsDomainRelated(nextDomain, resolution.Query())
}

func (udig *udigImpl) getRelatedDomains(resolutions []Resolution) (domains []string) {
Expand Down
30 changes: 22 additions & 8 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,19 @@ const (
)

var (
domainPattern = regexp.MustCompile(_domain)
ipPattern = regexp.MustCompile(_ip)
DefaultDomainRelation DomainRelationFn = func(domainA string, domainB string) bool {
return isDomainRelated(domainA, domainB, false)
}
StrictDomainRelation DomainRelationFn = func(domainA string, domainB string) bool {
return isDomainRelated(domainA, domainB, true)
}
IsDomainRelated = DefaultDomainRelation
domainPattern = regexp.MustCompile(_domain)
ipPattern = regexp.MustCompile(_ip)
)

type DomainRelationFn func(domainA string, domainB string) bool

func init() {
domainPattern.Longest()
}
Expand Down Expand Up @@ -81,7 +90,7 @@ func cleanDomain(domain string) string {
return strings.ToLower(domain)
}

func isDomainRelated(domainA string, domainB string) bool {
func isDomainRelated(domainA string, domainB string, strict bool) bool {
labelsA := dns.SplitDomainName(domainA)
labelsB := dns.SplitDomainName(domainB)

Expand All @@ -90,7 +99,10 @@ func isDomainRelated(domainA string, domainB string) bool {
return false
}

if len(labelsA) < 2 || len(labelsB) < 2 {
labelsALen := len(labelsA)
labelsBLen := len(labelsB)

if labelsALen < 2 || labelsBLen < 2 {
// Ignore TLDs.
return false
}
Expand All @@ -103,10 +115,12 @@ func isDomainRelated(domainA string, domainB string) bool {
//
// => Therefor we say the domains are related iff at least 2nd order domains are the same.

labelsALen := len(labelsA)
labelsBLen := len(labelsB)

return labelsA[labelsALen-2] == labelsB[labelsBLen-2]
related := labelsA[labelsALen-2] == labelsB[labelsBLen-2]
if related && strict {
// In strict mode we also require TLD match.
related = labelsA[labelsALen-1] == labelsB[labelsBLen-1]
}
return related
}

// reverseIPv4 returns a given IPv4 address in ARPA-like rDNS form.
Expand Down
82 changes: 82 additions & 0 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,85 @@ func Test_DissectDomainsFrom_By_invalid_domain(t *testing.T) {
assert.Len(t, domains, 1)
assert.Equal(t, "example.com", domains[0])
}

func Test_isDomainRelated_By_same_domain(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := domainA

// Execute.
res1 := isDomainRelated(domainA, domainB, false)
res2 := isDomainRelated(domainB, domainA, false)

// Assert.
assert.Equal(t, true, res1)
assert.Equal(t, true, res2)
}

func Test_isDomainRelated_By_subdomain(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := "sub.example.com"

// Execute.
res1 := isDomainRelated(domainA, domainB, false)
res2 := isDomainRelated(domainB, domainA, false)

// Assert.
assert.Equal(t, true, res1)
assert.Equal(t, true, res2)
}

func Test_isDomainRelated_By_domain_with_different_TLD(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := "sub.example.net"

// Execute.
res1 := isDomainRelated(domainA, domainB, false)
res2 := isDomainRelated(domainB, domainA, false)

// Assert.
assert.Equal(t, true, res1)
assert.Equal(t, true, res2)
}

func Test_isDomainRelated_By_domain_with_different_TLD_strict(t *testing.T) {
// Setup.
domainA := "example.com"
domainB := "sub.example.net"

// Execute.
res1 := isDomainRelated(domainA, domainB, true)
res2 := isDomainRelated(domainB, domainA, true)

// Assert.
assert.Equal(t, false, res1)
assert.Equal(t, false, res2)
}

func Test_isDomainRelated_By_TLDs(t *testing.T) {
// Setup.
domainA := "com"
domainB := "com"

// Execute.
res := isDomainRelated(domainA, domainB, false)

// Assert.
assert.Equal(t, false, res)
}

func Test_isDomainRelated_By_invalid_domain(t *testing.T) {
// Setup.
domainA := "."
domainB := "example.com"

// Execute.
res1 := isDomainRelated(domainA, domainB, false)
res2 := isDomainRelated(domainB, domainA, false)

// Assert.
assert.Equal(t, false, res1)
assert.Equal(t, false, res2)
}

0 comments on commit c1e7970

Please sign in to comment.